Compare commits

...

70 Commits

Author SHA1 Message Date
zms
918fe5452d 修正备选基站推送bug,增加切换日志 2025-02-27 15:10:18 +08:00
zms
38ba6f83a4 修正备选基站推送bug 2025-02-27 11:11:23 +08:00
zms
483aeb9d76 修正备选基站推送bug 2025-02-27 11:06:42 +08:00
zms
0a5bb0d7a1 添加备选基站 2025-02-24 15:44:23 +08:00
zms
3f0aa45cd9 添加备选基站 2025-02-24 14:41:26 +08:00
zms
c6fe8d403a Merge remote-tracking branch 'origin/master' into feature/beidou
# Conflicts:
#	sec-api/src/main/java/com/imdroid/secapi/dto/WarningCfg.java
#	sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/WarningServiceImpl.java
#	sec-beidou/src/main/java/com/imdroid/beidou/controller/WarningController.java
#	sec-beidou/src/main/resources/db/schema.sql
2025-02-24 14:21:17 +08:00
weidong
00634964fe 1、滤波结果跳变门限可配置,暂停自动停止推送功能 2025-02-22 17:07:42 +08:00
fengyarnom
fb77e8376d 修正一些 bug 2025-02-22 14:59:35 +08:00
fengyarnom
5519b14824 修正上个版本代码遗漏的Autowired注解 2025-02-22 11:27:20 +08:00
weidong
3b72967226 1、优化跟随处理 2025-02-22 10:15:29 +08:00
fengyarnom
d873278da9 1. 恢复状态查询和流量查询的频率 2025-02-22 09:44:40 +08:00
fengyarnom
1a7634b9a6 扩大线程池 2025-02-21 13:33:56 +08:00
fengyarnom
66c2b5c73a 移除异常告警测试 2025-02-21 13:14:26 +08:00
fengyarnom
6a30a8a572 调高状态查询和流量查询的频率,检查是否会出现问题 2025-02-21 12:36:17 +08:00
fengyarnom
efff574eb1 新增 ICCID 修改 2025-02-21 12:00:53 +08:00
fengyarnom
faff19e006 优化检查设备 SIM 卡 ICCID 的代码 2025-02-21 11:55:47 +08:00
fengyarnom
2cf8cd9479 解决ICCID更新失败的问题 2025-02-21 11:19:31 +08:00
fengyarnom
bb04326c3a 将发送 "AT+ICCID" 指令改为TCP通道 2025-02-21 10:49:05 +08:00
fengyarnom
a34451b783 修正 dtuAck 卫函数逻辑错误 2025-02-21 10:37:07 +08:00
fengyarnom
7a97945fc6 RTCM device 换成新增 ICCID 2025-02-21 10:15:09 +08:00
fengyarnom
bbe429fdca 新增 sim 卡流量不足和流量卡状态异常告警 2025-02-21 10:10:28 +08:00
fengyarnom
bd0b87c75d 新增sim卡流量查询和状态查询后台任务
1. 状态查询(每小时)
2. 流量查询 (每两小时)
2025-02-21 10:09:34 +08:00
fengyarnom
6d6a400dca 新增对 SIM 卡商的 HTTP 状态查询和流量查询接口 2025-02-21 10:07:21 +08:00
fengyarnom
aa0ef8625d 新增 SIM 卡前端页面 2025-02-21 10:06:22 +08:00
fengyarnom
43a1d36f18 新增simcard相关的数据结构 2025-02-21 10:04:09 +08:00
fengyarnom
1920906272 自检时检查设备的 ICCID 是否存在
1.若是不存在则发送“AT+ICCID”命令给 DTU 查询
2. 数据表 gnssdevices 需要新增:ALTER TABLE gnssdevices ADD COLUMN iccid VARCHAR(36) COMMENT 'ICCID号,唯一';
3. 新增 simcards 表
2025-02-21 10:01:57 +08:00
fengyarnom
74a0747a3c Merge remote-tracking branch 'origin/feature/beidou' into feature/beidou 2025-02-18 12:26:57 +08:00
fengyarnom
96a0ada3b7 修正 ICCID UDP 查询的测试代码 2025-02-18 12:25:45 +08:00
zms
6cd67adc19 将基站RTCM推入NtripCaster 2025-02-18 11:51:11 +08:00
fengyarnom
974e5025ec 新增 ICCID UDP 查询的测试代码 2025-02-18 11:47:12 +08:00
zms
8ea0dd64cd 允许手工设置解算结果有效/无效 2025-02-14 11:50:02 +08:00
zms
f1cf15a3a8 允许手工设置解算结果有效/无效 2025-02-13 18:35:44 +08:00
fengyarnom
6080c9646b Merge branch 'master' into feature/beidou 2025-02-12 17:44:05 +08:00
fengyarnom
b97aea602b Merge branch 'master' into feature/beidou
# Conflicts:
#	sec-beidou/src/main/java/com/imdroid/beidou/task/DeviceStatusChecker.java
#	sec-beidou/src/main/resources/templates/page/gnss_single_data.html
2025-01-16 18:12:05 +08:00
fengyarnom
7828c63634 在 schema.sql 添加 gnssdevicesinglerecords 表 2025-01-16 11:43:47 +08:00
fengyarnom
5fbb0c9ce3 关闭日志收集 2025-01-16 11:26:00 +08:00
fengyarnom
01cf1eec38 优化日志显示 2025-01-16 11:18:04 +08:00
fengyarnom
276fe2ee5e Merge branch 'master' into feature/beidou 2025-01-16 10:27:34 +08:00
fengyarnom
6d91cdee25 掉电警告触发日志收集 2024-11-28 15:29:52 +08:00
fengyarnom
3f3323df3d 1. 修正 日志 页面的搜索BUG
2. 优化 日志 页面的数据显示
2024-11-28 15:07:21 +08:00
fengyarnom
55849e2e76 1. 更改告警日志收集逻辑,只保存最近一个小时范围内的日志
2. 只监控连续无固定解
2024-11-28 11:48:55 +08:00
fengyarnom
69da1b6c94 Merge 'master' into 'feature/beidou' 2024-11-28 09:21:40 +08:00
fengyarnom
3cf0a6c4eb 移除不再使用的包 2024-11-25 11:04:54 +08:00
fengyarnom
e7d77b8936 新增检查设备是否需要冷启动的代码
- 新增 checkAndSendF9PColdStartCommand
- 新增 sendF9PColdStartCommand
2024-11-25 11:04:33 +08:00
fengyarnom
62ad3ae8a9 停用警告日志生成
- 删除在 DeviceStatusChecker 和 WarningServiceImpl 的相关代码
2024-11-21 18:03:22 +08:00
fengyarnom
09c05e4d17 Merge branch 'master' into feature/beidou
# Conflicts:
#	sec-beidou/src/main/resources/db/schema.sql
2024-11-21 15:31:59 +08:00
fengyarnom
9ed198a360 使用try-with-resources处理Stream 2024-11-06 17:08:41 +08:00
fengyarnom
3537aaa7e7 修改一些注释 2024-11-06 16:25:21 +08:00
fengyarnom
3c3ea56711 更新数据库 sql 文件 2024-11-06 16:21:37 +08:00
fengyarnom
6873bf04fa 优化单次解持久化保存 2024-11-06 16:21:16 +08:00
fengyarnom
c8d1e125da 修复单次解日志导出错误的问题 2024-11-06 16:20:43 +08:00
fengyarnom
bcc821ac60 merge: master into feature/beidou 2024-11-06 15:12:40 +08:00
fengyarnom
a2ec4bab66 merge: master into feature/beidou 2024-11-06 14:58:33 +08:00
fengyarnom
591cca2961 修改 menu 的名字 2024-11-05 10:14:39 +08:00
fengyarnom
af74263e19 修正错误的常量名字 2024-11-05 09:38:31 +08:00
fengyarnom
905796a7ea 新增单次解算缓存服务和页面控制类
- 新增 GnssSingleBufferService 服务类,用于持久化保存单次解算的结果
- 新增单次解算有关的页面控制类和前端页面
2024-11-05 09:37:08 +08:00
fengyarnom
27783443c2 单次解算记录持久化写入数据库
- 新增单次解析实体类与 Mapper
2024-11-05 09:32:06 +08:00
fengyarnom
9511027878 新增 Warning 文件生成目录配置 2024-11-01 15:51:03 +08:00
fengyarnom
01aa33fb8f 修正 WarningLogExecutor 的导致无法编译项目的错误 2024-11-01 15:50:21 +08:00
fengyarnom
783c7ee58b Merge branch 'master' into feature/logging 2024-10-31 14:50:43 +08:00
fengyarnom
11549788fe 当特定告警信息出现时(连续无固定解),收集特定站点的日志信息于 Warning 文件 2024-10-31 14:46:36 +08:00
fengyarnom
c0a05c909f 当特定告警信息出现时(电压低),收集特定站点的日志信息于 Warning 文件 2024-10-31 14:46:11 +08:00
fengyarnom
220f93fae5 优化执行器线程, 使用单线程去读写文件,以防止日志数据混乱
- 使用单线程
- 写入更多文件信息,方便查找问题
2024-10-31 14:44:53 +08:00
fengyarnom
c55b7ad024 优化线程 2024-10-31 11:32:38 +08:00
fengyarnom
ee2d627608 调整日志打印 2024-10-30 18:38:24 +08:00
fengyarnom
a826d34f9d 新增 特定设备出现告警时,统计日志记录于 Warning 文件
- 新增当检测到特定站点出现警告时,统计此站点的日志
2024-10-30 18:22:52 +08:00
fengyarnom
f45ade6dfa 调整日志打印逻辑
- 调整日志消息写入的逻辑
- 当出现非固定解时,D341 MessageExecutor 将此时的日志写入LOG文件
2024-10-30 18:20:07 +08:00
fengyarnom
9495bcfcdb 修正消息解码时,未将原码保存至 srcData 的问题 2024-10-30 18:11:08 +08:00
fengyarnom
b556a3349f 修正 D341 消息在线程中处理时,不会将消息原码拷贝至 srcData 的 BUG 2024-10-29 18:11:01 +08:00
fengyarnom
d86e547470 新增 loggingmode 字段于 gnssdevice 中,用于控制是否保存日志
- 前端 gnss_add_dev 页面增加日志控制的选项
- 数据表 GnssDevice 类 和 缓存 Device 类增加 loggingmode 字段属性,用于控制设备的日志是否保存于文件之中
- 数据库更改 gnssdevices 表,添加一个 SMALLINT 的 loggingmode 字段
2024-10-29 18:06:12 +08:00
44 changed files with 2241 additions and 64 deletions

View File

@ -17,7 +17,7 @@ public interface RtcmClient {
@GetMapping(value = "/get_device_info") @GetMapping(value = "/get_device_info")
public HttpResp getDeviceInfo(@RequestParam(name = "deviceId") String deviceId, @RequestParam(name = "cmd") String cmd); public HttpResp getDeviceInfo(@RequestParam(name = "deviceId") String deviceId, @RequestParam(name = "cmd") String cmd);
@PostMapping("/device_param_changed") @PostMapping("/device_param_changed")
HttpResp deviceParamChanged(@RequestParam(name = "deviceId") String deviceId,@RequestParam(name = "oldParentId") String oldParentId); HttpResp deviceParamChanged(@RequestParam(name = "deviceId") String deviceId,@RequestParam(name = "oldParentId") String oldParentId, @RequestParam("oldParentId1") String oldParentId1);
@PostMapping("/group_param_changed") @PostMapping("/group_param_changed")
HttpResp groupParamChanged(); HttpResp groupParamChanged();

View File

@ -40,6 +40,7 @@ public class GnssDevice {
private String fwddeviceid; //推送的设备名 private String fwddeviceid; //推送的设备名
private String name; private String name;
private String parentid; private String parentid;
private String parentid1;
private Integer devicetype; private Integer devicetype;
private String tenantname; private String tenantname;
private String project_id; private String project_id;
@ -65,5 +66,8 @@ public class GnssDevice {
// 日志记录控制 // 日志记录控制
private Short loggingmode; private Short loggingmode;
private String remark; private String remark;
private String iccid;
} }

View File

@ -22,6 +22,7 @@ public class GnssDeviceJoin {
private String fwddeviceid; //推送的设备名 private String fwddeviceid; //推送的设备名
private String name; private String name;
private String parentid; private String parentid;
private String parentid1;
private Integer devicetype; private Integer devicetype;
private String tenantname; private String tenantname;
private String project_id; private String project_id;

View File

@ -25,6 +25,7 @@ public class GnssGroup implements Serializable {
Short rs_adv; // reference station only Short rs_adv; // reference station only
Short power_mode; Short power_mode;
Integer device_num; Integer device_num;
Short gnss_sample_s;
public String getConfigCmd(GnssDevice device){ public String getConfigCmd(GnssDevice device){
String cmd = "D3110009"; String cmd = "D3110009";
@ -33,7 +34,8 @@ public class GnssGroup implements Serializable {
+HexUtil.Byte2HexString((byte) active_time.intValue()) +HexUtil.Byte2HexString((byte) active_time.intValue())
+HexUtil.Byte2HexString((byte) active_offset.intValue()) +HexUtil.Byte2HexString((byte) active_offset.intValue())
+((device.getDevicetype() == GnssDevice.TYPE_ROVER)?"00":HexUtil.Byte2HexString((byte) rs_adv.shortValue())) +((device.getDevicetype() == GnssDevice.TYPE_ROVER)?"00":HexUtil.Byte2HexString((byte) rs_adv.shortValue()))
+HexUtil.Byte2HexString((byte) power_mode.shortValue()); +HexUtil.Byte2HexString((byte) power_mode.shortValue())
+HexUtil.Byte2HexString((byte) gnss_sample_s.shortValue());
return cmd; return cmd;
} }

View File

@ -0,0 +1,51 @@
package com.imdroid.secapi.dto;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@TableName(value = "simcards")
public class SimCard {
public static final int STATUS_UNKNOWN = -1; // 未知
public static final int STATUS_WAIT_ACTIVE = 1; // 待激活
public static final int STATUS_ACTIVATED = 2; // 已激活
public static final int STATUS_SUSPENDED = 3; // 停机
public static final int STATUS_CANCELLED = 4; // 注销
public static final int STATUS_IN_STOCK = 5; // 库存
public static final int STATUS_TESTABLE = 6; // 可测试
public static final int STATUS_INVALID = 7; // 失效
public static final int STATUS_NOT_EXIST = 99; // 号码不存在
@TableId(type = IdType.AUTO)
@ExcelProperty("ID")
private Integer id;
@ExcelProperty("更新时间")
private Date updatetime;
@ExcelProperty("ICCID")
private String iccid;
@ExcelProperty("物联卡号码")
private String msisdn;
@ExcelProperty("设备ID")
private String deviceid;
@ExcelProperty("状态")
private Integer status;
@ExcelProperty("剩余流量(MB)")
private BigDecimal remaining;
@ExcelProperty("总流量(MB)")
private BigDecimal total;
@ExcelProperty("已用流量(MB)")
private BigDecimal used;
}

View File

@ -0,0 +1,40 @@
package com.imdroid.secapi.dto;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface SimCardsMapper extends MPJBaseMapper<SimCard>{
@Select({"select * from simcards where deviceid = #{deviceId} limit 1"})
SimCard queryByDeviceId(String deviceId);
@Select("select * from simcards where iccid = #{iccid} limit 1")
SimCard queryByIccid(String iccid);
@Update("UPDATE simcards SET " +
"updatetime = #{updatetime}, " +
"msisdn = #{msisdn}, " +
"status = #{status}, " +
"remaining = #{remaining}, " +
"total = #{total}, " +
"used = #{used} " +
"WHERE deviceid = #{deviceid}")
int updateSimCardInfo(SimCard simCard);
@Update("UPDATE simcards SET " +
"updatetime = #{updatetime}, " +
"msisdn = #{msisdn}, " +
"status = #{status} " +
"WHERE deviceid = #{deviceid}")
int updateCardStatusInfo(SimCard simCard);
@Update("UPDATE simcards SET " +
"updatetime = #{updatetime}, " +
"remaining = #{remaining}, " +
"total = #{total}, " +
"used = #{used} " +
"WHERE deviceid = #{deviceid}")
int updateCardTrafficInfo(SimCard simCard);
}

View File

@ -42,8 +42,15 @@ public class WarningCfg {
public static final String TYPE_NAME_CONT_INVALID_RESULT = "长时间无有效解"; public static final String TYPE_NAME_CONT_INVALID_RESULT = "长时间无有效解";
public static final int TYPE_INCLINE = 0x400; public static final int TYPE_INCLINE = 0x400;
public static final String TYPE_NAME_INCLINE = "异常倾斜"; public static final String TYPE_NAME_INCLINE = "异常倾斜";
public static final int TYPE_JUMP = 0x800; public static final int TYPE_SIM_STATUS_ABNORMAL = 0x800;
public static final String TYPE_NAME_JUMP = "滤波结果跳变"; public static final String TYPE_NAME_SIM_STATUS_ABNORMAL = "流量卡状态异常";
public static final int TYPE_SIM_LOW_TRAFFIC = 0x1000;
public static final String TYPE_NAME_SIM_LOW_TRAFFIC = "流量卡流量不足";
public static final int TYPE_XY_JUMP = 0x2000;
public static final String TYPE_NAME_XY_JUMP = "滤波结果水平跳变";
public static final int TYPE_Z_JUMP = 0x4000;
public static final String TYPE_NAME_Z_JUMP = "滤波结果高程跳变";
// warning level definition // warning level definition
public static final short LEVEL_0 = 0; //正常 public static final short LEVEL_0 = 0; //正常
@ -70,6 +77,8 @@ public class WarningCfg {
if((code & TYPE_NO_FIXED_RESULT) !=0) warningInfo.add(TYPE_NAME_NO_FIXED_RESULT); if((code & TYPE_NO_FIXED_RESULT) !=0) warningInfo.add(TYPE_NAME_NO_FIXED_RESULT);
if((code & TYPE_CONT_INVALID_RESULT) !=0) warningInfo.add(TYPE_NAME_CONT_INVALID_RESULT); if((code & TYPE_CONT_INVALID_RESULT) !=0) warningInfo.add(TYPE_NAME_CONT_INVALID_RESULT);
if((code & TYPE_INCLINE) !=0) warningInfo.add(TYPE_NAME_INCLINE); if((code & TYPE_INCLINE) !=0) warningInfo.add(TYPE_NAME_INCLINE);
if((code & TYPE_SIM_STATUS_ABNORMAL) !=0) warningInfo.add(TYPE_NAME_SIM_STATUS_ABNORMAL);
if((code & TYPE_SIM_LOW_TRAFFIC) !=0) warningInfo.add(TYPE_NAME_SIM_LOW_TRAFFIC);
return warningInfo; return warningInfo;
} }
} }

View File

@ -15,7 +15,7 @@ import static com.imdroid.sideslope.bd.GeoCoordConverterUtil.*;
*/ */
public class FocusCalculator3 extends FocusCalculator1{ public class FocusCalculator3 extends FocusCalculator1{
//final static long scale = 100000000L;//地球1°111km放大到mm乘以100,000,000 //final static long scale = 100000000L;//地球1°111km放大到mm乘以100,000,000
final static int bad_change_mm = 500;//固定解跳变连续10次超过500mm认为是周跳 final static int bad_change_mm = 300;//固定解跳变连续10次超过500mm认为是周跳
final static int bad_duration = 10; final static int bad_duration = 10;
int bad_count = 0; int bad_count = 0;
@ -61,10 +61,10 @@ public class FocusCalculator3 extends FocusCalculator1{
if(gga.isFixed()) { if(gga.isFixed()) {
counterFixedResult++; counterFixedResult++;
if(pointList.size()>0){ if(pointList.size()>0){
double[] lastXyz = pointList.get(pointList.size()-1); //double[] lastXyz = pointList.get(pointList.size()-1);
if(Math.abs(end[0]-lastXyz[0])>bad_change_mm || if(Math.abs(end[0]-referPoint[0])>bad_change_mm ||
Math.abs(end[1]-lastXyz[1])>bad_change_mm || Math.abs(end[1]-referPoint[1])>bad_change_mm ||
Math.abs(end[2]-lastXyz[2])>bad_change_mm){ Math.abs(end[2]-referPoint[2])>bad_change_mm){
bad_count++; bad_count++;
return; return;
} }

View File

@ -5,6 +5,9 @@ import com.imdroid.common.util.ByteUtil;
import com.imdroid.common.util.StringUtil; import com.imdroid.common.util.StringUtil;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static java.lang.Math.*; import static java.lang.Math.*;
@ -13,6 +16,110 @@ public class RtcmGgaUtil {
//gga样本*后面跟的是校验和其中76代表校验和对$和*之间的数据不包括这两个字符按字节进行异或运算二进制的结果 //gga样本*后面跟的是校验和其中76代表校验和对$和*之间的数据不包括这两个字符按字节进行异或运算二进制的结果
private static final String ggaExample = "$GNGGA,020850.50,2258.10508,N,11317.67958,E,4,12,0.74,3.9,M,-5.4,M,1.3,0000*76"; private static final String ggaExample = "$GNGGA,020850.50,2258.10508,N,11317.67958,E,4,12,0.74,3.9,M,-5.4,M,1.3,0000*76";
/**
* 提取多条rtcm
* 因为存在d331...rtcm...d331...rtcm..这样的数据
* 还存在d331...rtcm rtcm rtcm...这样的数据
* @param hex
* @return
*/
public static List<String> getRtcms(String hex){
return splitStartWith(hex,"d300","d301","d302").stream()
.map(com.imdroid.sideslope.bd.RtcmGgaUtil::getRtcm)
.filter(s -> s != null && !s.isEmpty())
.collect(Collectors.toList());
}
/**
* 提取一条rtcm
* @param hex
* @return
*/
public static String getRtcm(String hex){
try {
int index = getIndex(hex,"d300","d301","d302");
if (index != -1 && index < hex.length()-6) {
//d300数据长度
int length = Integer.parseInt(hex.substring(index + 3, index + 6), 16);
if(index + (3+length +3)*2 <= hex.length()){
return hex.substring(index, index + (3 + length + 3) * 2);
}
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
private static int getIndex(String... regex){
for (int i = 1; i < regex.length; i++) {
if(regex[0].contains(regex[i])){
return regex[0].indexOf(regex[i]);
}
}
return -1;
}
/**
* 按前缀切割分段
* @param regex 第一个是要处理的数据其他是要检测的前缀
* @return
*/
public static List<String> splitStartWith(String... regex){
ArrayList<String> list = new ArrayList<>();
try{
List<Integer> indexs = getIndexs(regex);
int start = 0;
for (int i = 0; i < indexs.size(); i++) {
if(indexs.get(i) != 0){
list.add(regex[0].substring(start,indexs.get(i)));
start = indexs.get(i);
}
if(i == indexs.size() -1){
list.add(regex[0].substring(indexs.get(i)));
}
}
}catch (Exception e){
e.printStackTrace();
}
return list;
}
/**
* 按多个规则搜索索引
* @param regex
* @return
*/
public static List<Integer> getIndexs(String... regex){
List<Integer> list =new ArrayList<>();
for (int i = 1; i < regex.length; i++) {
list.addAll(findAllIndex(regex[0],0,regex[i]));
}
list.sort((o1, o2) -> o1-o2);
return list;
}
/**
* 按规则搜索所有索引
* @param string
* @param index
* @param findStr
* @return
*/
public static List<Integer> findAllIndex(String string, int index, String findStr){
List<Integer> list =new ArrayList<>();
int num = string.indexOf(findStr,index);
if(num != -1){
list.add(num);
//递归进行查找
List myList = findAllIndex(string,num+1,findStr);
list.addAll(myList);
}
return list;
}
/** /**
* 获取rtcm数据类型 * 获取rtcm数据类型
* @param bytes * @param bytes

View File

@ -4,13 +4,16 @@ import com.imdroid.common.util.DataTypeUtil;
import com.imdroid.common.util.ThreadManager; import com.imdroid.common.util.ThreadManager;
import com.imdroid.secapi.client.BeidouClient; import com.imdroid.secapi.client.BeidouClient;
import com.imdroid.secapi.dto.GnssDevice; import com.imdroid.secapi.dto.GnssDevice;
import com.imdroid.common.util.ByteUtil;
import com.imdroid.sideslope.bd.Gga; import com.imdroid.sideslope.bd.Gga;
import com.imdroid.sideslope.message.D331RtcmMessage; import com.imdroid.sideslope.message.D331RtcmMessage;
import com.imdroid.sideslope.ntrip.UdpNtripServer;
import com.imdroid.sideslope.sal.Device; import com.imdroid.sideslope.sal.Device;
import com.imdroid.sideslope.sal.DeviceService; import com.imdroid.sideslope.sal.DeviceService;
import com.imdroid.sideslope.server.DeviceChannel; import com.imdroid.sideslope.server.DeviceChannel;
import com.imdroid.sideslope.server.OnlineChannels; import com.imdroid.sideslope.server.OnlineChannels;
import com.imdroid.sideslope.service.DataPersistService; import com.imdroid.sideslope.service.DataPersistService;
import com.imdroid.sideslope.bd.RtcmGgaUtil;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -20,7 +23,12 @@ import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* @author Layton * @author Layton
@ -31,39 +39,87 @@ public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void>
private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final Map<String ,Boolean> deviceBackupStatus = new ConcurrentHashMap<>();
@Resource(name = "local") @Resource(name = "local")
private DeviceService deviceService; private DeviceService deviceService;
@Autowired @Autowired
private BeidouClient beidouClient; private BeidouClient beidouClient;
@Autowired @Autowired
private DataPersistService dataPersistService; private DataPersistService dataPersistService;
@Override @Override
public Void execute(D331RtcmMessage message) { public Void execute(D331RtcmMessage message) {
String id = message.getId(); String id = message.getId();
byte[] srcdata = message.getSrcData();
String rtcm = ByteUtil.bytesToHexString(srcdata);
// 补齐tenantId // 补齐tenantId
Device deviceBs = deviceService.findByDeviceId(id); Device deviceBs = deviceService.findByDeviceId(id);
if(deviceBs == null || deviceBs.getOpMode() == GnssDevice.OP_MODE_UNUSE) return null; if(deviceBs == null || deviceBs.getOpMode() == GnssDevice.OP_MODE_UNUSE) return null;
// 添加NTRIP处理
ntrip(id, rtcm);
// 推送基站数据 // 推送基站数据
if(deviceBs.getOpMode() == GnssDevice.OP_MODE_USE) { if(deviceBs.getOpMode() == GnssDevice.OP_MODE_USE) {
byte[] forwardBytes = message.getSrcData(); byte[] forwardBytes = message.getSrcData();
// 要求快速转发因此用缓存不要每次都查数据库 // 获取使用该基站(包括作为主基站和备选基站)的所有测站
List<Device> deviceList = deviceService.findByParentId(id); List<Device> primaryDevices = deviceService.findByParentId(id);
//logger.debug("base station {} has {} rovers: ", message.getId(),deviceList.size()); List<Device> backupDevices = deviceService.findByParentId1(id);
// 合并两个列表
List<Device> allDevices = new ArrayList<>();
allDevices.addAll(primaryDevices);
allDevices.addAll(backupDevices);
DeviceChannel deviceChannel = null; DeviceChannel deviceChannel = null;
for (Device device : deviceList) { for (Device device : allDevices) {
if (device.getOpMode() != GnssDevice.OP_MODE_USE) continue; if (device.getOpMode() != GnssDevice.OP_MODE_USE) continue;
String deviceId = device.getDeviceId(); String deviceId = device.getDeviceId();
if(device.getDataChannelType() == Device.CHANNEL_TYPE_UDP) {
deviceChannel = OnlineChannels.INSTANCE.getDataChannel(deviceId); // 检查该设备是否应该接收此基站的数据
String primaryBaseId = device.getParentId();
String backupBaseId = device.getParentId1();
// 如果当前基站是该设备的备选基站需要检查主基站是否离线
if (id.equals(backupBaseId)) {
byte[] modifyData = forwardBytes.clone();
Device primaryBase = deviceService.findByDeviceId(primaryBaseId);
// 如果主基站仍然在线则跳过备选基站的数据
if (primaryBase != null && isBaseStationOnline(primaryBase)) {
if(deviceBackupStatus.remove(deviceId) != null){
logger.info("设备 {} 从备用基站 {} 切换回主基站 {}",
deviceId, id, primaryBaseId);
}
continue;
} }
else { else {
String hexPrimaryBase = String.format("%06x",Integer.parseInt(primaryBaseId));
if(deviceBackupStatus.putIfAbsent(deviceId,true) == null){
logger.info("设备 {} 从主基站 {} 切换到备用基站 {}",
deviceId, primaryBaseId, id);
}
modifyData[5] = (byte) Integer.parseInt(hexPrimaryBase.substring(0,2),16);
modifyData[6] = (byte) Integer.parseInt(hexPrimaryBase.substring(2,4),16);
modifyData[7] = (byte) Integer.parseInt(hexPrimaryBase.substring(4,6),16);
forwardBytes = modifyData;
// 打印修改后的完整数据16进制形式
//logger.info("Modified D331 data (HEX): {}", ByteUtil.bytesToHexString(forwardBytes));
}
}
// 获取设备通道并发送数据
if(device.getDataChannelType() == Device.CHANNEL_TYPE_UDP) {
deviceChannel = OnlineChannels.INSTANCE.getDataChannel(deviceId);
} else {
deviceChannel = OnlineChannels.INSTANCE.getConfigChannel(deviceId); deviceChannel = OnlineChannels.INSTANCE.getConfigChannel(deviceId);
} }
if(deviceChannel != null && deviceChannel.isOnline()) { if(deviceChannel != null && deviceChannel.isOnline()) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("forward d331 rtcm to device {}", deviceId); logger.debug("forward d331 rtcm from {} to device {}", id, deviceId);
} }
if (deviceId.startsWith("2307")) { if (deviceId.startsWith("2307")) {
forwardBytes[2] = (byte) (forwardBytes[2] & 0x07);//兼容不带序号的测站 forwardBytes[2] = (byte) (forwardBytes[2] & 0x07);//兼容不带序号的测站
@ -115,11 +171,9 @@ public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void>
Gga gga = message.getGga(); Gga gga = message.getGga();
if(gga != null) { if(gga != null) {
deviceBs.updateSatelitesNum(gga.getSatellitesInUsed()); deviceBs.updateSatelitesNum(gga.getSatellitesInUsed());
//if(gga.isFixed()) { //基站的quality不会是4
deviceBs.setLatitude(gga.getLatitude()); deviceBs.setLatitude(gga.getLatitude());
deviceBs.setLongitude(gga.getLongitude()); deviceBs.setLongitude(gga.getLongitude());
deviceBs.setAltitude(gga.getAltitude()); deviceBs.setAltitude(gga.getAltitude());
//}
} }
ThreadManager.getFixedThreadPool().submit(() -> { ThreadManager.getFixedThreadPool().submit(() -> {
@ -133,8 +187,43 @@ public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void>
return null; return null;
} }
private void ntrip(String mountpoint, String hexData) {
try {
// 将原始字节转换为16进制字符串用于RTCM提取
//String hexData = ByteUtil.bytesToHexString(rawData);
System.out.println(hexData);
// 提取RTCM数据并发送到NtripServer,使用设备ID作为挂载点
Optional.ofNullable(RtcmGgaUtil.getRtcms(hexData))
.ifPresent(rtcm -> {
//System.out.println("挂载点: " + mountpoint);
//System.out.println("RTCM数据: " + rtcm);
UdpNtripServer.send(mountpoint, rtcm);
});
} catch (Exception e) {
logger.error("处理NTRIP数据失败, 挂载点: {}, 错误: {}", mountpoint, e.getMessage());
}
}
@Override @Override
public Class<?> getMessageType() { public Class<?> getMessageType() {
return D331RtcmMessage.class; return D331RtcmMessage.class;
} }
/**
* 判断住基站是否在线
* @param baseStation 基站
* @return 是否在线
*/
private boolean isBaseStationOnline(Device baseStation){
if(baseStation == null) return false;
LocalDateTime now =LocalDateTime.now();
return baseStation.getLastRxTime() !=null &&
baseStation.getLastRxTime().isAfter(now.minusMinutes(10));
}
} }

View File

@ -4,6 +4,7 @@ import com.imdroid.common.util.DataTypeUtil;
import com.imdroid.common.util.HexUtil; import com.imdroid.common.util.HexUtil;
import com.imdroid.common.util.ThreadManager; import com.imdroid.common.util.ThreadManager;
import com.imdroid.secapi.client.BeidouClient; import com.imdroid.secapi.client.BeidouClient;
import com.imdroid.secapi.client.HttpResp;
import com.imdroid.secapi.dto.*; import com.imdroid.secapi.dto.*;
import com.imdroid.sideslope.message.D3F0SelfCheckMessage; import com.imdroid.sideslope.message.D3F0SelfCheckMessage;
import com.imdroid.sideslope.sal.Device; import com.imdroid.sideslope.sal.Device;
@ -16,7 +17,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -41,6 +44,8 @@ public class D3F0SelfCheckMessageExecutor implements Executor<D3F0SelfCheckMessa
@Autowired @Autowired
private DataPersistService dataPersistService; private DataPersistService dataPersistService;
@Autowired @Autowired
private GnssDeviceMapper gnssDeviceMapper;
@Autowired
GnssMsgMapper msgMapper; GnssMsgMapper msgMapper;
@Autowired @Autowired
@ -66,6 +71,8 @@ public class D3F0SelfCheckMessageExecutor implements Executor<D3F0SelfCheckMessa
device.updateRx(message.getHeader(),message.getLen(),1); device.updateRx(message.getHeader(),message.getLen(),1);
ThreadManager.getFixedThreadPool().submit(() -> { ThreadManager.getFixedThreadPool().submit(() -> {
// 检查是否需要更新设备的 ICCID
checkAndAskICCID(device);
// 检查是否需要对设备的F9P进行冷启动操作 // 检查是否需要对设备的F9P进行冷启动操作
if(device.getDeviceType() == Device.DEVICE_ROVER){ if(device.getDeviceType() == Device.DEVICE_ROVER){
if(device.getModel() == GnssDevice.MODEL_G505){ if(device.getModel() == GnssDevice.MODEL_G505){
@ -179,6 +186,28 @@ public class D3F0SelfCheckMessageExecutor implements Executor<D3F0SelfCheckMessa
rtcmClient.config(device.getDeviceId(), sendCmd); rtcmClient.config(device.getDeviceId(), sendCmd);
} }
void checkAndAskICCID(Device device){
// 如果设备的 ICCID 存在那么就不用发送 "AT+ICCID" 指令
if(device.getIccid() != null && !device.getIccid().trim().isEmpty()){
GnssDevice gnssDevice = gnssDeviceMapper.queryByDeviceId(device.getDeviceId());
if(gnssDevice.getIccid() != null && !gnssDevice.getIccid().trim().isEmpty()){
// 状态和流量查询更新需要 1-2 小时期间 DataPersistService 更新可能不及时
// 若是数据库的设备已经更新了 iccid 将它同步到 DataPersistService 缓存中
device.setIccid(gnssDevice.getIccid());
}
return;
}
String sendCmd = "AT+ICCID";
int msgType = 0xD310 + 10; // DTU
short len = (short) (sendCmd.length() + 5);
sendCmd = Integer.toHexString(msgType) + HexUtil.Short2HexString(len)+
HexUtil.Int2HexString(Integer.parseInt(device.getDeviceId()))+
"01"+HexUtil.String2HexString(sendCmd);
rtcmClient.config(device.getDeviceId(),sendCmd);
// TODO 将这个消息写到 msg 表中
logger.info(sendCmd);
}
private void checkAndResetBTGnss(Device device){ private void checkAndResetBTGnss(Device device){
if(device.getNoFixedAndFloatResult()>0 &&device.getAbnormalD341Num()>10){ if(device.getNoFixedAndFloatResult()>0 &&device.getAbnormalD341Num()>10){
if(isBaseStationFwd(device)) startBTResetTask(device); if(isBaseStationFwd(device)) startBTResetTask(device);

View File

@ -0,0 +1,31 @@
package com.imdroid.sideslope.ntrip;
import com.imdroid.common.util.HttpUtils;
import com.imdroid.common.util.ThreadManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author likongyong
* @date 2023/10/19 11:49
*/
public class HttpNtripServer {
private static final Logger logger = LoggerFactory.getLogger(HttpNtripServer.class);
/**
* 修改挂载点获取xingyu差分的gga
* @param mount
* @param gga
*/
public static void sendGGA(String mount, String gga){
ThreadManager.getSingleThreadPool(HttpNtripServer.class.getName()).execute(()->{
try{
String url = "http://localhost:11001/ntrip/sendGGA/" + mount + "/" + gga;
String result = HttpUtils.getUrl(url);
logger.debug("{} send gga {} {}",mount, gga, result);
}catch (Exception e){
logger.error(e.toString());
}
});
}
}

View File

@ -0,0 +1,69 @@
package com.imdroid.sideslope.ntrip;
import com.imdroid.common.util.ByteUtil;
import com.imdroid.common.util.ThreadManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.List;
/**
* 本地udp发送差分数据到ntrip-forward-server项目
*/
public class UdpNtripServer {
private static final Logger logger = LoggerFactory.getLogger(UdpNtripServer.class);
private static DatagramSocket socket;
private static DatagramPacket outPacket;
/**
* 向某挂载点提供差分信息
* @param mount 挂载点名称
* @param hexRtcm 差分信息16进制字符串
*/
public static void send(String mount, String hexRtcm){
ThreadManager.getSingleThreadPool(UdpNtripServer.class.getName()).execute(()->{
try{
//随机端口
if(socket == null) socket = new DatagramSocket();
if(outPacket == null) outPacket = new DatagramPacket(new byte[0],0, InetAddress.getByName("localhost"),11100);
outPacket.setData(encode(ByteUtil.addBytes(mount.getBytes(), ByteUtil.hexStringTobyte(hexRtcm))));
socket.send(outPacket);
}catch (Exception e){
socket = null;
outPacket = null;
e.printStackTrace();
}
});
}
/**
* 向某挂载点提供差分信息
* @param mount 挂载点名称
* @param hexRtcm 差分信息16进制字符串
*/
public static void send(String mount, List<String> hexRtcm){
logger.debug(mount + ":" + hexRtcm.size());
for (String s : hexRtcm) {
send(mount,s);
}
}
//加入校验位用于校验数据是否完整
private static byte[] encode(byte[] bytes) {
byte[] bytes1 = new byte[bytes.length + 1];
//校验位
byte b = bytes[0];
bytes1[0] = bytes[0];
for (int i = 1; i < bytes.length; i++) {
b ^= bytes[i];
bytes1[i] = bytes[i];
}
bytes1[bytes1.length - 1] = b;
return bytes1;
}
}

View File

@ -32,6 +32,7 @@ public class DbDeviceServiceImpl implements DeviceService {
device.setDeviceType(gnssDevice.getDevicetype()); device.setDeviceType(gnssDevice.getDevicetype());
device.setModel(gnssDevice.getModel()); device.setModel(gnssDevice.getModel());
device.setParentId(gnssDevice.getParentid()); device.setParentId(gnssDevice.getParentid());
device.setParentId1(gnssDevice.getParentid1());
device.setName(gnssDevice.getName()); device.setName(gnssDevice.getName());
device.setProjectId(gnssDevice.getProject_id()); device.setProjectId(gnssDevice.getProject_id());
device.setCalcGroupId(gnssDevice.getCalc_group_id()); device.setCalcGroupId(gnssDevice.getCalc_group_id());
@ -44,6 +45,7 @@ public class DbDeviceServiceImpl implements DeviceService {
device.setEcefy(gnssDevice.getEcefy()); device.setEcefy(gnssDevice.getEcefy());
device.setEcefz(gnssDevice.getEcefz()); device.setEcefz(gnssDevice.getEcefz());
device.setLoggingmode(gnssDevice.getLoggingmode()); device.setLoggingmode(gnssDevice.getLoggingmode());
device.setIccid(gnssDevice.getIccid());
return device; return device;
} }
@ -58,6 +60,36 @@ public class DbDeviceServiceImpl implements DeviceService {
device.setDeviceId(gnssDevice.getDeviceid()); device.setDeviceId(gnssDevice.getDeviceid());
device.setDeviceType(gnssDevice.getDevicetype()); device.setDeviceType(gnssDevice.getDevicetype());
device.setParentId(gnssDevice.getParentid()); device.setParentId(gnssDevice.getParentid());
device.setParentId1(gnssDevice.getParentid1());
device.setName(gnssDevice.getName());
device.setProjectId(gnssDevice.getProject_id());
device.setCalcGroupId(gnssDevice.getCalc_group_id());
device.setOpMode(gnssDevice.getOpmode());
device.setFwdId(gnssDevice.getFwd_group_id());
device.setIPose(gnssDevice.getIpose());
device.setIPosn(gnssDevice.getIposn());
device.setIPosd(gnssDevice.getIposd());
device.setEcefx(gnssDevice.getEcefx());
device.setEcefy(gnssDevice.getEcefy());
device.setEcefz(gnssDevice.getEcefz());
deviceList.add(device);
}
return deviceList;
}
@Override
public List<Device> findByParentId1(String parentId1) {
QueryWrapper<GnssDevice> query = new QueryWrapper<>();
query.eq("parentid1", parentId1);
List<GnssDevice> gnssDeviceList = gnssDeviceRepository.selectList(query);
List<Device> deviceList = new ArrayList<>(gnssDeviceList.size());
for (GnssDevice gnssDevice : gnssDeviceList) {
Device device = new Device();
device.setDeviceId(gnssDevice.getDeviceid());
device.setDeviceType(gnssDevice.getDevicetype());
device.setParentId(gnssDevice.getParentid());
device.setParentId1(gnssDevice.getParentid1()); // 添加备选基站ID
device.setName(gnssDevice.getName()); device.setName(gnssDevice.getName());
device.setProjectId(gnssDevice.getProject_id()); device.setProjectId(gnssDevice.getProject_id());
device.setCalcGroupId(gnssDevice.getCalc_group_id()); device.setCalcGroupId(gnssDevice.getCalc_group_id());

View File

@ -1,10 +1,12 @@
package com.imdroid.sideslope.sal; package com.imdroid.sideslope.sal;
import com.alibaba.excel.annotation.ExcelProperty;
import com.imdroid.secapi.dto.GnssDevice; import com.imdroid.secapi.dto.GnssDevice;
import com.imdroid.sideslope.bd.Gga; import com.imdroid.sideslope.bd.Gga;
import com.imdroid.sideslope.bd.UBXUtil; import com.imdroid.sideslope.bd.UBXUtil;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/** /**
@ -35,6 +37,7 @@ public class Device {
private String deviceId; private String deviceId;
private String parentId; private String parentId;
private String parentId1;
private String projectId; private String projectId;
private String fwdId; private String fwdId;
@ -67,6 +70,11 @@ public class Device {
Double iPosn; Double iPosn;
Double iPosd; Double iPosd;
String iccid;
private BigDecimal remaining;
private BigDecimal total;
private BigDecimal used;
LocalDateTime lastRxTime; LocalDateTime lastRxTime;
LocalDateTime lastD3f2Time; LocalDateTime lastD3f2Time;
short noFixedAndFloatResult=0; short noFixedAndFloatResult=0;

View File

@ -11,4 +11,6 @@ public interface DeviceService {
Device findByDeviceId(String deviceId); Device findByDeviceId(String deviceId);
List<Device> findByParentId(String parentId); List<Device> findByParentId(String parentId);
List<Device> findByParentId1(String parentId1);
} }

View File

@ -7,6 +7,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -57,6 +58,22 @@ public class LocalDeviceServiceImpl implements DeviceService {
return device; return device;
} }
@Override
public List<Device> findByParentId1(String parentId1) {
if (parentId1 == null || parentId1.trim().isEmpty()){
return new ArrayList<>();
}
List<Device> device = subDeviceCache.getIfPresent("backup_" + parentId1); // 使用前缀区分备选基站的缓存
if (device == null) {
logger.debug("backup base station {} refresh: " + parentId1);
device = delegate.findByParentId1(parentId1);
if (device != null) {
subDeviceCache.put("backup_" + parentId1, device);
}
}
return device;
}
public void refresh(String deviceId, String oldParentId){ public void refresh(String deviceId, String oldParentId){
Device device = deviceCache.getIfPresent(deviceId); Device device = deviceCache.getIfPresent(deviceId);
if (device != null) { if (device != null) {
@ -66,6 +83,10 @@ public class LocalDeviceServiceImpl implements DeviceService {
subDeviceCache.invalidate(oldParentId); subDeviceCache.invalidate(oldParentId);
} }
} }
if(device.getParentId1() != null && !device.getParentId1().trim().isEmpty()){
subDeviceCache.invalidate("back_"+device.getParentId1());
}
deviceCache.invalidate(deviceId); deviceCache.invalidate(deviceId);
} }
} }

View File

@ -0,0 +1,20 @@
package com.imdroid.sideslope.service;
import com.imdroid.sideslope.sal.Device;
import com.imdroid.sideslope.simcard.*;
public interface SimCardQueryService {
// 查询卡基本信息
BaseResponse<CardInfoData> queryCardInfo(Device device);
// 查询卡状态
BaseResponse<CardStatusData> queryCardStatus(Device device);
// 查询流量信息
BaseResponse<GprsData> queryGprs(Device device);
// 查询卡详细信息
BaseResponse<CardDetailData> queryCardDetail(Device device);
}

View File

@ -0,0 +1,179 @@
package com.imdroid.sideslope.service;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imdroid.secapi.dto.GnssStatusJoin;
import com.imdroid.secapi.dto.SimCard;
import com.imdroid.secapi.dto.SimCardsMapper;
import com.imdroid.sideslope.sal.Device;
import com.imdroid.sideslope.sal.DeviceService;
import com.imdroid.sideslope.simcard.*;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.util.*;
@Service
public class SimCardQueryServiceImpl implements SimCardQueryService{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final String BASE_URL = "http://120.78.169.220:8089";
private static final String USERNAME = "gzyzdz";
private static final String KEY = "632629d1269a202c9d49a574623e4e4c";
@Resource(name = "local")
private DeviceService deviceService;
@Autowired
SimCardsMapper simCardsMapper;
@Override
public BaseResponse<CardInfoData> queryCardInfo(Device device) {
return executeQuery(device, "/api/Service/Cardinfo", CardInfoData.class);
}
@Override
public BaseResponse<CardStatusData> queryCardStatus(Device device) {
return executeQuery(device, "/api/Service/QueryCardStatus", CardStatusData.class);
}
@Override
public BaseResponse<GprsData> queryGprs(Device device) {
return executeQuery(device, "/api/Service/QueryGprs", GprsData.class);
}
@Override
public BaseResponse<CardDetailData> queryCardDetail(Device device) {
return executeQuery(device, "/api/Service/QueryCard", CardDetailData.class);
}
private <T> BaseResponse<T> executeQuery(Device device, String path, Class<T> responseType) {
try {
Map<String, String> params = new HashMap<>();
params.put("username", USERNAME);
params.put("key", KEY);
params.put("card", device.getIccid());
params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
String signature = calculateSignature(params);
params.put("signature", signature);
logger.info("Request params: {}", params);
String response = sendHttpPost(path, params);
logger.info("查询响应: 设备={}, ICCID={}, 响应={}",
device.getDeviceId(), device.getIccid(), response);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
// 特殊处理CardStatus的数组响应
if (responseType == CardStatusData.class) {
JsonNode root = mapper.readTree(response);
if (root.get("Status").asInt() == 1 && root.get("Data").isArray()) {
CardStatusData statusData = new CardStatusData();
statusData.setStatusCode(root.get("Data").get(0).asInt());
statusData.setStatusDesc(root.get("Data").get(1).asText());
BaseResponse<CardStatusData> baseResponse = new BaseResponse<>();
baseResponse.setStatus(1);
baseResponse.setMessage("Success");
baseResponse.setData(statusData);
return (BaseResponse<T>) baseResponse;
}
}
JavaType type = mapper.getTypeFactory().constructParametricType(BaseResponse.class, responseType);
return mapper.readValue(response, type);
} catch (Exception e) {
logger.error("查询失败: 设备={}, 错误={}", device.getDeviceId(), e.getMessage());
return null;
}
}
private String calculateSignature(Map<String, String> params) {
try {
List<String> paramList = new ArrayList<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
paramList.add(entry.getKey() + "=" + entry.getValue());
}
Collections.sort(paramList);
String paramString = String.join("&", paramList);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(paramString.getBytes());
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
String signature = sb.toString();
logger.debug("Signature: {}", signature);
return signature;
} catch (Exception e) {
logger.error("签名计算失败: {}", e.getMessage());
return null;
}
}
private String sendHttpPost(String path, Map<String, String> params) throws Exception {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(BASE_URL + path);
List<BasicNameValuePair> pairs = new ArrayList<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
httpPost.setEntity(new UrlEncodedFormEntity(pairs));
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
return EntityUtils.toString(response.getEntity());
}
}
}
public boolean hasValidIccid(Device device) {
return device.getIccid() != null && !device.getIccid().trim().isEmpty();
}
public SimCard CreateOrUpdateSimCard(Device device) {
SimCard simCard = simCardsMapper.queryByDeviceId(device.getDeviceId());
if (simCard == null) {
simCard = createNewSimCard(device);
}
return simCard;
}
public SimCard createNewSimCard(Device device) {
SimCard newCard = new SimCard();
newCard.setDeviceid(device.getDeviceId());
newCard.setUpdatetime(new Date());
newCard.setIccid(device.getIccid());
newCard.setStatus(-1);
newCard.setMsisdn("");
newCard.setRemaining(BigDecimal.ZERO);
newCard.setUsed(BigDecimal.ZERO);
newCard.setTotal(BigDecimal.ZERO);
simCardsMapper.insert(newCard);
return newCard;
}
public boolean isValidResponse(BaseResponse<?> response) {
return response != null && response.getStatus() == 1;
}
}

View File

@ -3,7 +3,6 @@ package com.imdroid.sideslope.service;
import com.imdroid.secapi.dto.GnssCalcData; import com.imdroid.secapi.dto.GnssCalcData;
import com.imdroid.secapi.dto.GnssStatus; import com.imdroid.secapi.dto.GnssStatus;
import com.imdroid.secapi.dto.GnssStatusMsg; import com.imdroid.secapi.dto.GnssStatusMsg;
import com.imdroid.secapi.dto.GnssTrxMsg;
import com.imdroid.sideslope.sal.Device; import com.imdroid.sideslope.sal.Device;
public interface WarningService { public interface WarningService {

View File

@ -12,6 +12,8 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@ -65,7 +67,7 @@ public class WarningServiceImpl implements WarningService {
isUpdated = true; isUpdated = true;
} }
// 无固定解 // b562
if(check(status, WarningCfg.TYPE_LESS_B562, if(check(status, WarningCfg.TYPE_LESS_B562,
WarningCfg.TYPE_NAME_LESS_B562,true, WarningCfg.TYPE_NAME_LESS_B562,true,
device.getFixedNum(),null, device.getFixedNum(),null,
@ -216,7 +218,7 @@ public class WarningServiceImpl implements WarningService {
curStatus.setWarningcode(curStatus.getWarningcode() | warningType); curStatus.setWarningcode(curStatus.getWarningcode() | warningType);
// 新告警出现后生成对应设备的 warning 日志文件 // 新告警出现后生成对应设备的 warning 日志文件
//generate_warning_logs(curStatus.getDeviceid(),warningType,auxInfo); //generate_warning_logs(curStatus.getDeviceid(),warningType,warningName);
} }
isUpdated = true; isUpdated = true;
} }
@ -259,6 +261,152 @@ public class WarningServiceImpl implements WarningService {
} }
} }
} }
/*
// 检查SIM卡状态
public void checkSimCardStatus(Device device, SimCard simCard) {
GnssStatus status = gnssStatusMapper.getByDeviceId(device.getDeviceId());
if (status == null) return;
boolean isUpdated = false;
// 检查SIM卡状态是否异常停机注销失效
if (simCard.getStatus() == SimCard.STATUS_SUSPENDED ||
simCard.getStatus() == SimCard.STATUS_CANCELLED ||
simCard.getStatus() == SimCard.STATUS_INVALID) {
String statusDesc;
switch(simCard.getStatus()) {
case SimCard.STATUS_SUSPENDED:
statusDesc = "停机";
break;
case SimCard.STATUS_CANCELLED:
statusDesc = "注销";
break;
case SimCard.STATUS_INVALID:
statusDesc = "失效";
break;
default:
statusDesc = "未知状态";
}
if (check(status, WarningCfg.TYPE_SIM_STATUS_ABNORMAL,
WarningCfg.TYPE_NAME_SIM_STATUS_ABNORMAL, false,
simCard.getStatus(), null,
"SIM卡状态: " + statusDesc)) {
isUpdated = true;
}
} else if (simCard.getStatus() == SimCard.STATUS_ACTIVATED) {
// 状态正常已激活清除告警
if ((status.getWarningcode() & WarningCfg.TYPE_SIM_STATUS_ABNORMAL) != 0) {
clearWarning(status, WarningCfg.TYPE_SIM_STATUS_ABNORMAL);
isUpdated = true;
}
}
if (isUpdated) {
status.setWarning(getWarningLevel(status.getWarningcode()));
gnssStatusMapper.updateById(status);
}
}
public void checkSimCardTraffic(Device device, SimCard simCard) {
GnssStatus status = gnssStatusMapper.getByDeviceId(device.getDeviceId());
if (status == null) return;
boolean isUpdated = false;
BigDecimal usedPercentage = simCard.getUsed()
.divide(simCard.getTotal(), 4, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(100));
// 检查流量使用情况
if (check(status, WarningCfg.TYPE_SIM_LOW_TRAFFIC,
WarningCfg.TYPE_NAME_SIM_LOW_TRAFFIC,
false, // 大于等于流量门限值那么就报警
usedPercentage.intValue(),
null,
String.format("流量已使用 %.2f%%", usedPercentage.doubleValue()))) {
isUpdated = true;
}
if (isUpdated) {
status.setWarning(getWarningLevel(status.getWarningcode()));
gnssStatusMapper.updateById(status);
}
}
*/
// 检查SIM卡状态
public void checkSimCardStatus(Device device, SimCard simCard) {
GnssStatus status = gnssStatusMapper.getByDeviceId(device.getDeviceId());
if (status == null) return;
boolean isUpdated = false;
// 检查SIM卡状态是否异常停机注销失效
if (simCard.getStatus() == SimCard.STATUS_SUSPENDED ||
simCard.getStatus() == SimCard.STATUS_CANCELLED ||
simCard.getStatus() == SimCard.STATUS_INVALID) {
String statusDesc;
switch(simCard.getStatus()) {
case SimCard.STATUS_SUSPENDED:
statusDesc = "停机";
break;
case SimCard.STATUS_CANCELLED:
statusDesc = "注销";
break;
case SimCard.STATUS_INVALID:
statusDesc = "失效";
break;
default:
statusDesc = "未知状态";
}
if (check(status, WarningCfg.TYPE_SIM_STATUS_ABNORMAL,
WarningCfg.TYPE_NAME_SIM_STATUS_ABNORMAL, false,
simCard.getStatus(), null,
"SIM卡状态: " + statusDesc)) {
isUpdated = true;
}
} else if (simCard.getStatus() == SimCard.STATUS_ACTIVATED) {
// 状态正常已激活清除告警
if ((status.getWarningcode() & WarningCfg.TYPE_SIM_STATUS_ABNORMAL) != 0) {
clearWarning(status, WarningCfg.TYPE_SIM_STATUS_ABNORMAL);
isUpdated = true;
}
}
if (isUpdated) {
status.setWarning(getWarningLevel(status.getWarningcode()));
gnssStatusMapper.updateById(status);
}
}
public void checkSimCardTraffic(Device device, SimCard simCard) {
GnssStatus status = gnssStatusMapper.getByDeviceId(device.getDeviceId());
if (status == null) return;
boolean isUpdated = false;
BigDecimal usedPercentage = simCard.getUsed()
.divide(simCard.getTotal(), 4, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(100));
// 检查流量使用情况
if (check(status, WarningCfg.TYPE_SIM_LOW_TRAFFIC,
WarningCfg.TYPE_NAME_SIM_LOW_TRAFFIC,
false, // 大于等于流量门限值那么就报警
usedPercentage.intValue(),
null,
String.format("流量已使用 %.2f%%", usedPercentage.doubleValue()))) {
isUpdated = true;
}
if (isUpdated) {
status.setWarning(getWarningLevel(status.getWarningcode()));
gnssStatusMapper.updateById(status);
}
}
public void generate_warning_logs(String device_id,int warning_type,String warning_type_name){ public void generate_warning_logs(String device_id,int warning_type,String warning_type_name){
// 连续无固定解 掉电 警告 // 连续无固定解 掉电 警告
@ -286,9 +434,22 @@ public class WarningServiceImpl implements WarningService {
@Override @Override
public void checkFilteredResultJump(double[] latestRpos, GnssCalcData locationRecord){ public void checkFilteredResultJump(double[] latestRpos, GnssCalcData locationRecord){
if(Math.abs(locationRecord.getRpose()-latestRpos[0])>2 || int[] warningValuesXY = cfgMap.get(WarningCfg.TYPE_XY_JUMP);
Math.abs(locationRecord.getRposn()-latestRpos[1])>2 || int[] warningValuesZ = cfgMap.get(WarningCfg.TYPE_Z_JUMP);
Math.abs(locationRecord.getRposd()-latestRpos[2])>4){ int warningCode = 0;
if(warningValuesXY!=null){
if(Math.abs(locationRecord.getRpose()-latestRpos[0])>warningValuesXY[1] ||
Math.abs(locationRecord.getRposn()-latestRpos[1])>warningValuesXY[1]){
warningCode = WarningCfg.TYPE_XY_JUMP;
}
}
if(warningCode==0 && warningValuesZ!=null){
if(Math.abs(locationRecord.getRposd()-latestRpos[2])>warningValuesZ[1]){
warningCode = WarningCfg.TYPE_Z_JUMP;
}
}
if(warningCode!=0){
// 停止推送 // 停止推送
QueryWrapper<GnssDevice> queryWrapper = new QueryWrapper<>(); QueryWrapper<GnssDevice> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid",locationRecord.getDeviceid()); queryWrapper.eq("deviceid",locationRecord.getDeviceid());
@ -300,13 +461,13 @@ public class WarningServiceImpl implements WarningService {
!unFwdGroupName.equals(device.getFwd_group_id())){ !unFwdGroupName.equals(device.getFwd_group_id())){
device.setFwd_group_id(unFwdGroupName); device.setFwd_group_id(unFwdGroupName);
device.setFwd_group_id2(unFwdGroupName); device.setFwd_group_id2(unFwdGroupName);
deviceMapper.updateById(device); //deviceMapper.updateById(device);
// 产生告警 // 产生告警
WarningMsg warningMsg = new WarningMsg(); WarningMsg warningMsg = new WarningMsg();
warningMsg.setDeviceid(device.getDeviceid()); warningMsg.setDeviceid(device.getDeviceid());
warningMsg.setTenantid(device.getTenantid()); warningMsg.setTenantid(device.getTenantid());
warningMsg.setCreatetime(LocalDateTime.now()); warningMsg.setCreatetime(LocalDateTime.now());
warningMsg.setCode(WarningCfg.TYPE_JUMP); warningMsg.setCode(warningCode);
warningMsg.setLevel(WarningCfg.LEVEL_2); warningMsg.setLevel(WarningCfg.LEVEL_2);
double deltaE = locationRecord.getRpose()-latestRpos[0]; double deltaE = locationRecord.getRpose()-latestRpos[0];
double deltaN = locationRecord.getRposn()-latestRpos[1]; double deltaN = locationRecord.getRposn()-latestRpos[1];

View File

@ -0,0 +1,10 @@
package com.imdroid.sideslope.simcard;
import lombok.Data;
@Data
public class BaseResponse<T> {
private Integer status;
private String message;
private T data;
}

View File

@ -0,0 +1,38 @@
package com.imdroid.sideslope.simcard;
import lombok.Data;
@Data
public class CardDetailData {
private Integer operatortype;
private String activetime;
private String starttime;
private String stoptime;
private String silentdate;
private Integer status;
private String msisdn;
private String iccid;
private String imsi;
private Integer packageid;
private String packagename;
private String net;
private GprsInfo gprs;
private ApnInfo apn;
@Data
public static class GprsInfo {
private Double total;
private Double used;
private Double left;
}
@Data
public static class ApnInfo {
private String apnid;
private String status;
private String ip;
private String rat;
private String onoffstatus;
}
}

View File

@ -0,0 +1,10 @@
package com.imdroid.sideslope.simcard;
import lombok.Data;
@Data
public class CardInfoData {
private String imsi;
private String msisdn;
private String iccid;
}

View File

@ -0,0 +1,10 @@
package com.imdroid.sideslope.simcard;
import lombok.Data;
@Data
public class CardStatusData {
private Integer statusCode;
private String statusDesc;
}

View File

@ -0,0 +1,41 @@
package com.imdroid.sideslope.simcard;
import lombok.Data;
import java.util.List;
@Data
public class GprsData {
private Integer operatortype;
private List<GprsUsage> gps;
@Data
public static class GprsUsage {
private Double left;
private Double total;
private Double used;
}
// 返回数据格式
// {
// "Status": 1,
// "Message": "Success",
// "Data": {
// "operatortype": 1,
// "GPS": [
// {
// "Left": "2023",
// "Total": "2.0",
// "Used": "25"
// }
// ]
// }
// }
public GprsUsage getFirstGprsUsage() {
if (gps != null && !gps.isEmpty()) {
return gps.get(0);
}
return null;
}
}

View File

@ -0,0 +1,209 @@
package com.imdroid.sideslope.task;
import com.alibaba.excel.util.StringUtils;
import com.imdroid.common.util.ThreadManager;
import com.imdroid.secapi.dto.*;
import com.imdroid.sideslope.sal.Device;
import com.imdroid.sideslope.sal.DeviceService;
import com.imdroid.sideslope.service.SimCardQueryServiceImpl;
import com.imdroid.sideslope.service.WarningServiceImpl;
import com.imdroid.sideslope.simcard.BaseResponse;
import com.imdroid.sideslope.simcard.CardInfoData;
import com.imdroid.sideslope.simcard.CardStatusData;
import com.imdroid.sideslope.simcard.GprsData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Component
@Configuration
@EnableScheduling
public class SimStatusChecker {
// SIM 卡流量和状态查询定时任务
// 1. 每小时任务
// a. 通过CardInfo 检查 iccid sim卡号
// b. 通过QueryCardStatus 检查SIM卡当前的状态
// 2. 每两小时任务
// a. QueryGprs 检查 SIM 流量
final Logger logger = LoggerFactory.getLogger(SimStatusChecker.class);
@Autowired
private GnssStatusMapper gnssStatusMapper;
@Autowired
private WarningServiceImpl warningService;
@Autowired
private SimCardsMapper simCardsMapper;
@Resource(name = "local")
private DeviceService deviceService;
@Autowired
private SimCardQueryServiceImpl simCardQueryServiceImpl;
// 每小时执行一次状态检查调度
@Scheduled(cron = "0 0 * * * ?")
//@Scheduled(cron = "0 */10 * * * ?")
private void scheduleSimCardStatusCheck() {
List<GnssStatusJoin> onlineDevices = gnssStatusMapper.queryOnline();
logger.info("当前在线设备数量: {}", onlineDevices.size());
for (GnssStatusJoin onlineDevice : onlineDevices) {
int delay = Math.abs(onlineDevice.getDeviceid().hashCode() % 3600 );
logger.info("- 设备: {}, SIM状态查询延迟执行: {}秒", onlineDevice.getDeviceid(), delay);
ThreadManager.getScheduledThreadPool().schedule(
() -> checkDeviceSimCardStatus(onlineDevice.getDeviceid()),
delay,
TimeUnit.SECONDS
);
}
}
// 每两小时执行一次流量检查调度
@Scheduled(cron = "0 0 0/2 * * ?")
private void scheduleSimCardTrafficCheck() {
List<GnssStatusJoin> onlineDevices = gnssStatusMapper.queryOnline();
logger.info("当前在线设备数量: {}", onlineDevices.size());
for (GnssStatusJoin onlineDevice : onlineDevices) {
int delay = Math.abs(onlineDevice.getDeviceid().hashCode() % 7200);
logger.debug("- 设备: {}, SIM流量查询延迟执行: {}秒", onlineDevice.getDeviceid(), delay);
ThreadManager.getScheduledThreadPool().schedule(
() -> checkDeviceSimCardTraffic(onlineDevice.getDeviceid()),
delay,
TimeUnit.SECONDS
);
}
}
private void checkDeviceSimCardStatus(String deviceId) {
try {
Device device = deviceService.findByDeviceId(deviceId);
// 不允许尚未从自检得到 ICCID 的设备参加 SIM 卡状态查询
if (!simCardQueryServiceImpl.hasValidIccid(device)) {
return;
}
// SimCards 表中没有数据就初始化这其实说明它在自检中刚获得属于自己的 ICCID
SimCard simCard = simCardQueryServiceImpl.CreateOrUpdateSimCard(device);
updateSimCardInfo(device, simCard);
} catch (Exception e) {
logger.error("设备{}状态查询失败: ", deviceId, e);
}
}
private void checkDeviceSimCardTraffic(String deviceId) {
try {
Device device = deviceService.findByDeviceId(deviceId);
// 不允许尚未从自检得到 ICCID 的设备参加 SIM 卡状态查询
if (!simCardQueryServiceImpl.hasValidIccid(device)) {
return;
}
// SimCards 表中没有数据就初始化这说明它在自检中获得属于自己的 ICCID
SimCard simCard = simCardQueryServiceImpl.CreateOrUpdateSimCard(device);
// 如果该卡状态不是已激活而是其他状态那么不运行它参与 SIM 卡流量检测
if(simCard.getStatus() != SimCard.STATUS_ACTIVATED){
return;
}
updateSimCardTrafficFromAPI(device, simCard);
} catch (Exception e) {
logger.error("设备{}查询失败: ", deviceId, e);
}
}
private void updateSimCardInfo(Device device, SimCard simCard) throws Exception {
// 自检中只是获取保存了设备的 ICCID 所有如果判断如果没有 MSISDN先更新基本信息
if (StringUtils.isBlank(simCard.getMsisdn())) {
updateSimCardBasicInfoFromAPI(device, simCard);
}
// 更新状态
updateSimCardStatusFromAPI(device, simCard);
}
private void updateSimCardBasicInfoFromAPI(Device device, SimCard simCard) {
try {
BaseResponse<CardInfoData> response = simCardQueryServiceImpl.queryCardInfo(device);
if (!simCardQueryServiceImpl.isValidResponse(response)) {
return;
}
CardInfoData info = response.getData();
simCard.setUpdatetime(new Date());
simCard.setMsisdn(info.getMsisdn());
simCardsMapper.updateSimCardInfo(simCard);
logger.info("更新SIM卡基本信息 - imsi: {}, msisdn: {}, iccid: {}",
info.getImsi(), info.getMsisdn(), info.getIccid());
} catch (Exception e) {
logger.error("更新设备{}的SIM卡基本信息失败: ", device.getDeviceId(), e);
throw e;
}
}
private void updateSimCardStatusFromAPI(Device device, SimCard simCard) {
try {
BaseResponse<CardStatusData> response = simCardQueryServiceImpl.queryCardStatus(device);
if (!simCardQueryServiceImpl.isValidResponse(response)) {
return;
}
CardStatusData status = response.getData();
simCard.setUpdatetime(new Date());
simCard.setStatus(status.getStatusCode());
simCardsMapper.updateCardStatusInfo(simCard);
warningService.checkSimCardStatus(device, simCard);
logger.info("更新SIM卡状态 - Code: {}, 描述: {}",
status.getStatusCode(), status.getStatusDesc());
} catch (Exception e) {
logger.error("更新设备{}的SIM卡状态失败: ", device.getDeviceId(), e);
// throw e;
}
}
private void updateSimCardTrafficFromAPI(Device device, SimCard simCard) {
try {
BaseResponse<GprsData> response = simCardQueryServiceImpl.queryGprs(device);
if (!simCardQueryServiceImpl.isValidResponse(response)) {
return;
}
GprsData gprsData = response.getData();
GprsData.GprsUsage usage = gprsData.getFirstGprsUsage();
if (usage == null) {
logger.warn("无可用流量数据查询, deviceId: {}", device.getDeviceId());
return;
}
simCard.setUpdatetime(new Date());
simCard.setRemaining(BigDecimal.valueOf(usage.getLeft()));
simCard.setUsed(BigDecimal.valueOf(usage.getUsed()));
simCard.setTotal(BigDecimal.valueOf(usage.getTotal()));
simCardsMapper.updateCardTrafficInfo(simCard);
warningService.checkSimCardTraffic(device, simCard);
logger.info("更新流量信息成功 - deviceId: {}, 剩余: {}MB, 总量: {}MB, 已用: {}MB",
device.getIccid(),
simCard.getRemaining(),
simCard.getTotal(),
simCard.getUsed());
} catch (Exception e) {
logger.error("设备{}更新SIM卡流量失败: ", device.getDeviceId(), e);
//throw e;
}
}
}

View File

@ -59,6 +59,9 @@ public class APIController extends BasicController{
//转成字符串 //转成字符串
String dtuAck = configAck.substring(9*2); String dtuAck = configAck.substring(9*2);
rxInfo += configAck+"("+HexUtil.HexString2String(dtuAck)+")"; rxInfo += configAck+"("+HexUtil.HexString2String(dtuAck)+")";
// 检查是否需要更新 ICCID
updateICCID(device,dtuAck);
} }
else if(msgType == 0xd313&&configAck.length()>=100){ else if(msgType == 0xd313&&configAck.length()>=100){
//转成字符串 //转成字符串
@ -192,4 +195,18 @@ public class APIController extends BasicController{
msgMapper.insert(gnssMsg); msgMapper.insert(gnssMsg);
} }
void updateICCID(GnssDevice device, String dtuAck) {
// 只检查 "ICCID:" 的十六进制部分
if(!dtuAck.contains("49434349443a")){
return;
}
String content = HexUtil.HexString2String(dtuAck);
if(content.contains("+ICCID:")){
System.out.println(content);
String iccid = content.substring(content.indexOf("+ICCID:") + 8).trim();
iccid = iccid.split("\r\n")[0].trim();
device.setIccid(iccid);
deviceMapper.updateById(device);
}
}
} }

View File

@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import java.awt.*;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -54,6 +55,44 @@ public class GnssCalcDataController extends BasicController implements CommonExc
return "/page/gnss_data_calc"; return "/page/gnss_data_calc";
} }
@ResponseBody
@RequestMapping("/page/gnssUpdateEnabled")
public String gnssUpdateEnabled(HttpSession session, HttpServletRequest request) {
try {
String deviceId = request.getParameter("deviceid");
String createTimeStr = request.getParameter("createtime");
String enabledStr = request.getParameter("enabled");
if (deviceId == null || createTimeStr == null || enabledStr == null) {
return "数据无效";
}
// 转换为Boolean类型
Boolean enabled = "1".equals(enabledStr);
GnssCalcData updateData = new GnssCalcData();
updateData.setEnabled(enabled); // 使用Boolean类型
updateData.setUpdatetime(LocalDateTime.now());
QueryWrapper<GnssCalcData> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid", deviceId)
.eq("createtime", createTimeStr);
int result = dataMapper.update(updateData, queryWrapper);
System.out.println(result);
if (result > 0) {
return "success";
} else {
return "更新失败";
}
} catch (Exception e) {
e.printStackTrace();
return "更新过程中发生错误: " + e.getMessage();
}
}
/**** 推送数据 *****/ /**** 推送数据 *****/
@RequestMapping("/gnss/data/list_calc") @RequestMapping("/gnss/data/list_calc")
@ResponseBody @ResponseBody

View File

@ -24,6 +24,7 @@ import javax.servlet.http.HttpSession;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
@Controller @Controller
public class GnssDeviceController extends BasicController{ public class GnssDeviceController extends BasicController{
@ -115,6 +116,11 @@ public class GnssDeviceController extends BasicController{
if (StringUtils.hasText(parentid)) { if (StringUtils.hasText(parentid)) {
queryWrapper.like("parentid", parentid); queryWrapper.like("parentid", parentid);
} }
//备选基站
String parentid1 = search.getString("parentid1");
if (StringUtils.hasText(parentid1)){
queryWrapper.like("parentid1", parentid1);
}
//项目号 //项目号
String project_id = search.getString("project_id"); String project_id = search.getString("project_id");
if (StringUtils.hasText(project_id)) { if (StringUtils.hasText(project_id)) {
@ -123,7 +129,9 @@ public class GnssDeviceController extends BasicController{
//所属组织 //所属组织
String tenantname = search.getString("tenantname"); String tenantname = search.getString("tenantname");
if (StringUtils.hasText(tenantname)) { if (StringUtils.hasText(tenantname)) {
queryWrapper.like("tenantname", tenantname); if(tenantname.startsWith("非SAAS"))
queryWrapper.ne("tenantname",Tenant.SAAS_PROVIDER_NAME);
else queryWrapper.like("tenantname", tenantname);
} }
//设备类型 //设备类型
Integer devicetype = search.getInteger("devicetype"); Integer devicetype = search.getInteger("devicetype");
@ -206,7 +214,9 @@ public class GnssDeviceController extends BasicController{
OpLogManager.OP_OBJ_DEVICE, OpLogManager.OP_OBJ_DEVICE,
device.getDeviceid() + " update: " + diff); device.getDeviceid() + " update: " + diff);
device.setUpdatetime(LocalDateTime.now()); device.setUpdatetime(LocalDateTime.now());
if(!old_device.getGroup_id().equals(device.getGroup_id())){ if(!old_device.getGroup_id().equals(device.getGroup_id())||
!old_device.getParentid().equals(device.getParentid())||
!Objects.equals(old_device.getParentid1(),device.getParentid1())){
device.setSyn(false); device.setSyn(false);
} }
num = gnssDeviceMapper.updateById(device); num = gnssDeviceMapper.updateById(device);
@ -227,7 +237,7 @@ public class GnssDeviceController extends BasicController{
} else { } else {
// 更新组参数的关联个数 // 更新组参数的关联个数
updateBasicGroupAssociatedNum(device,old_device); updateBasicGroupAssociatedNum(device,old_device);
rtcmClient.deviceParamChanged(device.getDeviceid(), device.getParentid()); rtcmClient.deviceParamChanged(device.getDeviceid(), device.getParentid(), device.getParentid1());
return HttpResult.ok(); return HttpResult.ok();
} }
} }
@ -349,7 +359,7 @@ public class GnssDeviceController extends BasicController{
if (num == 0) { if (num == 0) {
return HttpResult.failed(); return HttpResult.failed();
} else{ } else{
rtcmClient.deviceParamChanged(del_id, null); rtcmClient.deviceParamChanged(del_id, null, null);
return HttpResult.ok(); return HttpResult.ok();
} }
} }

View File

@ -0,0 +1,213 @@
package com.imdroid.beidou.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.imdroid.beidou.common.Role;
import com.imdroid.beidou.service.CommonExcelService;
import com.imdroid.secapi.dto.*;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@Controller
public class SimCardController extends BasicController {
// TODO这里的常量应该写入 application.properties
private static final String BASE_URL = "http://120.78.169.220:8089";
private static final String USERNAME = "gzyzdz";
private static final String KEY = "632629d1269a202c9d49a574623e4e4c";
@Autowired
private SimCardsMapper simCardsMapper;
@RequestMapping("/page/sim_status")
public String simStatus(Model m, HttpSession session) {
initModel(m, session);
return "/page/sim_status";
}
@RequestMapping("/sim/list")
@ResponseBody
public JSONObject list(HttpSession session,
int page,
int limit,
String searchType,
String searchContent,
Integer status) {
Page<SimCard> pageable = new Page<>(page, limit);
QueryWrapper<SimCard> queryWrapper = new QueryWrapper<>();
if (!StringUtils.isEmpty(searchContent)) {
switch(searchType) {
case "deviceId":
queryWrapper.like("deviceid", searchContent.trim());
break;
case "iccid":
queryWrapper.like("iccid", searchContent.trim());
break;
case "simNumber":
queryWrapper.like("msisdn", searchContent.trim());
break;
}
}
if (status != null) {
queryWrapper.eq("status", status);
}
queryWrapper.orderByDesc("updatetime");
IPage<SimCard> cs = simCardsMapper.selectPage(pageable, queryWrapper);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 0);
jsonObject.put("msg", "");
jsonObject.put("count", cs.getTotal());
jsonObject.put("data", cs.getRecords());
System.out.println(jsonObject.toString());
return jsonObject;
}
@RequestMapping("/page/sim_traffic_query")
public String simTrafficQuery(Model m, HttpSession session) {
initModel(m, session);
return "/page/sim_traffic_query";
}
// 代理转发
@RequestMapping("/api/proxy/sim/query")
@ResponseBody
public JSONObject proxySimQuery(
@RequestParam String type,
@RequestParam String content
){
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
try {
Map<String, String> params = new HashMap<>();
params.put("username", USERNAME);
params.put("key", KEY);
switch(type) {
case "iccid":
params.put("card", content);
break;
case "deviceId":
if (content.trim().isEmpty()) {
throw new IllegalArgumentException("设备ID不能为空");
}
SimCard simCard = simCardsMapper.queryByDeviceId(content.trim());
if (simCard == null) {
throw new IllegalArgumentException("未找到该设备ID对应的SIM卡信息");
}
params.put("card", simCard.getIccid());
break;
case "simNumber":
params.put("card", content);
break;
default:
throw new IllegalArgumentException("无效的查询类型: " + type);
}
params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
String signature = calculateSignature(params);
if (signature == null) {
throw new Exception("签名计算失败");
}
StringBuilder urlBuilder = new StringBuilder(BASE_URL);
urlBuilder.append("/api/Service/QueryCard?");
urlBuilder.append("username=").append(USERNAME);
urlBuilder.append("&key=").append(KEY);
urlBuilder.append("&card=").append(params.get("card"));
urlBuilder.append("&timestamp=").append(params.get("timestamp"));
urlBuilder.append("&signature=").append(signature);
httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(urlBuilder.toString());
// System.out.println("Sending request: " + urlBuilder.toString());
response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
// System.out.println("Received response: " + result);
return JSONObject.parseObject(result);
} catch (Exception e) {
// System.out.println("Query failed: " + e.getMessage());
JSONObject errorResponse = new JSONObject();
errorResponse.put("Status", 0);
errorResponse.put("Message", "查询失败: " + e.getMessage());
return errorResponse;
} finally {
try {
if (response != null) {
response.close();
}
if (httpClient != null) {
httpClient.close();
}
} catch (Exception e) {
}
}
}
private String calculateSignature(Map<String, String> params) {
try {
List<String> paramList = new ArrayList<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
paramList.add(entry.getKey() + "=" + entry.getValue());
}
Collections.sort(paramList);
String paramString = String.join("&", paramList);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(paramString.getBytes());
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
String signature = sb.toString();
// System.out.println("Signature: " + signature);
return signature;
} catch (Exception e) {
//System.out.println("Signature: " + e.getMessage());
return null;
}
}
}

View File

@ -47,6 +47,14 @@ public class WarningController extends BasicController implements CommonExcelSer
warningMap.put(WarningCfg.TYPE_LOW_RSSI, WarningCfg.TYPE_NAME_LOW_RSSI); warningMap.put(WarningCfg.TYPE_LOW_RSSI, WarningCfg.TYPE_NAME_LOW_RSSI);
warningMap.put(WarningCfg.TYPE_RX_MUCH_UNKNOWN, WarningCfg.TYPE_NAME_RX_MUCH_UNKNOWN); warningMap.put(WarningCfg.TYPE_RX_MUCH_UNKNOWN, WarningCfg.TYPE_NAME_RX_MUCH_UNKNOWN);
warningMap.put(WarningCfg.TYPE_INCLINE, WarningCfg.TYPE_NAME_INCLINE); warningMap.put(WarningCfg.TYPE_INCLINE, WarningCfg.TYPE_NAME_INCLINE);
warningMap.put(WarningCfg.TYPE_SIM_LOW_TRAFFIC, WarningCfg.TYPE_NAME_SIM_LOW_TRAFFIC);
warningMap.put(WarningCfg.TYPE_SIM_STATUS_ABNORMAL, WarningCfg.TYPE_NAME_SIM_STATUS_ABNORMAL);
warningMap.put(WarningCfg.TYPE_SIM_LOW_TRAFFIC, WarningCfg.TYPE_NAME_SIM_LOW_TRAFFIC);
warningMap.put(WarningCfg.TYPE_SIM_STATUS_ABNORMAL, WarningCfg.TYPE_NAME_SIM_STATUS_ABNORMAL);
warningMap.put(WarningCfg.TYPE_XY_JUMP, WarningCfg.TYPE_NAME_XY_JUMP);
warningMap.put(WarningCfg.TYPE_Z_JUMP, WarningCfg.TYPE_NAME_Z_JUMP);
} }
/**** 推送页面 *****/ /**** 推送页面 *****/

View File

@ -43,6 +43,7 @@ public class DeviceStatusChecker {
@Autowired @Autowired
GnssDeviceMapper deviceMapper; GnssDeviceMapper deviceMapper;
static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Scheduled(cron = "0 18,48 * * * ?") // 每半时执行一次 @Scheduled(cron = "0 18,48 * * * ?") // 每半时执行一次

View File

@ -68,6 +68,7 @@ CREATE TABLE IF NOT EXISTS `gnssdevices` (
`imei` varchar(16) DEFAULT NULL, `imei` varchar(16) DEFAULT NULL,
`model` smallint DEFAULT 0, `model` smallint DEFAULT 0,
`loggingmode` smallint DEFAULT 0 COMMENT '日志模式: 0-精简模式(仅D3F0和D3F2), 1-完整模式', `loggingmode` smallint DEFAULT 0 COMMENT '日志模式: 0-精简模式(仅D3F0和D3F2), 1-完整模式',
`iccid` VARCHAR(36) DEFAULT NULL COMMENT 'ICCID号唯一',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@ -78,6 +79,7 @@ CREATE TABLE IF NOT EXISTS `gnssgroup` (
`active_time` int DEFAULT 6, `active_time` int DEFAULT 6,
`active_offset` int DEFAULT 0, `active_offset` int DEFAULT 0,
`rs_adv` smallint DEFAULT 0, `rs_adv` smallint DEFAULT 0,
`gnss_sample_s` smallint DEFAULT 1,
`power_mode` smallint DEFAULT 0, `power_mode` smallint DEFAULT 0,
`device_num` int DEFAULT 0, `device_num` int DEFAULT 0,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
@ -215,7 +217,6 @@ CREATE TABLE IF NOT EXISTS `gnsstrxmsg` (
`uart2unknown` int DEFAULT NULL, `uart2unknown` int DEFAULT NULL,
`b562bytes` int DEFAULT NULL, `b562bytes` int DEFAULT NULL,
`d3xxbytes` int DEFAULT NULL, `d3xxbytes` int DEFAULT NULL,
`b562count` int DEFAULT NULL,
`satelliteinuse` int DEFAULT 0, `satelliteinuse` int DEFAULT 0,
`fixnum` int DEFAULT NULL, `fixnum` int DEFAULT NULL,
`floatnum` int DEFAULT NULL, `floatnum` int DEFAULT NULL,
@ -327,6 +328,9 @@ CREATE TABLE IF NOT EXISTS `ApiKey` (
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/***
GNSS
*/
CREATE TABLE IF NOT EXISTS `gnssdevicesinglerecords` ( CREATE TABLE IF NOT EXISTS `gnssdevicesinglerecords` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`deviceid` varchar(64) NOT NULL COMMENT '设备ID', `deviceid` varchar(64) NOT NULL COMMENT '设备ID',
@ -341,6 +345,26 @@ CREATE TABLE IF NOT EXISTS `gnssdevicesinglerecords` (
KEY `idx_createtime` (`createtime`) KEY `idx_createtime` (`createtime`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='GNSS单次解算记录表'; ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='GNSS单次解算记录表';
/***
SIM卡记录表
*/
CREATE TABLE IF NOT EXISTS `simcards` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,唯一',
`updatetime` DATETIME DEFAULT NULL COMMENT '最新一次查询接口记录的时间',
`iccid` VARCHAR(36) NOT NULL COMMENT 'ICCID号唯一',
`msisd` VARCHAR(20) NOT NULL COMMENT '物联卡号码SIM号唯一',
`deviceid` VARCHAR(20) DEFAULT NULL COMMENT '设备ID号',
`status` TINYINT DEFAULT -1 COMMENT 'SIM卡状态-1:未知, 1:待激活, 2:已激活, 3:停机, 4:注销, 5:库存, 6:可测试, 7:失效, 99:号码不存在)',
`remaining` DECIMAL(10,2) DEFAULT 0.00 COMMENT '剩余流量单位为MB保留两位小数',
`total` DECIMAL(10,2) DEFAULT 0.00 COMMENT '总流量单位为MB保留两位小数',
`used` DECIMAL(10,2) DEFAULT 0.00 COMMENT '已用流量单位为MB保留两位小数',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_iccid` (`iccid`),
UNIQUE KEY `uk_msisd` (`msisd`),
INDEX `idx_deviceid` (`deviceid`),
INDEX `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='SIM卡信息表';
CREATE TABLE IF NOT EXISTS `ehm` ( CREATE TABLE IF NOT EXISTS `ehm` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenantid` int DEFAULT 0, `tenantid` int DEFAULT 0,

View File

@ -117,6 +117,26 @@
} }
] ]
}, },
{
"title": "SIM卡管理",
"href": "",
"icon": "fa fa-signal",
"target": "_self",
"child": [
{
"title": "总览",
"href": "page/sim_status",
"icon": "fa fa-minus",
"target": "_self"
},
{
"title": "卡信息查询",
"href": "page/sim_traffic_query",
"icon": "fa fa-minus",
"target": "_self"
}
]
},
{ {
"title": "数据推送", "title": "数据推送",
"href": "", "href": "",

View File

@ -93,6 +93,26 @@
} }
] ]
}, },
{
"title": "SIM卡管理",
"href": "",
"icon": "fa fa-signal",
"target": "_self",
"child": [
{
"title": "总览",
"href": "page/sim_status",
"icon": "fa fa-minus",
"target": "_self"
},
{
"title": "卡信息查询",
"href": "page/sim_traffic_query",
"icon": "fa fa-minus",
"target": "_self"
}
]
},
{ {
"title": "数据推送", "title": "数据推送",
"href": "", "href": "",

View File

@ -98,7 +98,9 @@
</div> </div>
<script type="text/html" id="currentTableBar"> <script type="text/html" id="currentTableBar">
<a class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="cmd">命令行</a> <a class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="edit">状态修改</a>
<!-- <a class="layui-btn layui-btn-xs layui-btn-danger data-count-delete" lay-event="delete">删除</a>-->
<!-- <a class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="cmd"></a>-->
</script> </script>
</div> </div>
@ -129,7 +131,8 @@
{field: 'r9250e', title: '拟合东', templet: "<div>{{d.r9250e==null?'':d.r9250e.toFixed(2)}}</div>"}, {field: 'r9250e', title: '拟合东', templet: "<div>{{d.r9250e==null?'':d.r9250e.toFixed(2)}}</div>"},
{field: 'r9250n', title: '拟合北', templet: "<div>{{d.r9250n==null?'':d.r9250n.toFixed(2)}}</div>"}, {field: 'r9250n', title: '拟合北', templet: "<div>{{d.r9250n==null?'':d.r9250n.toFixed(2)}}</div>"},
{field: 'r9250d', title: '拟合天', templet: "<div>{{d.r9250d==null?'':d.r9250d.toFixed(2)}}</div>"}, {field: 'r9250d', title: '拟合天', templet: "<div>{{d.r9250d==null?'':d.r9250d.toFixed(2)}}</div>"},
{field: 'enabled', title: '有效',templet: '#enabledTrans'} {field: 'enabled', title: '有效',templet: '#enabledTrans'},
{title: '操作', toolbar: '#currentTableBar', fixed: "right", width: 120}
]; ];
if([[${role}]] != "SUPER_ADMIN") { if([[${role}]] != "SUPER_ADMIN") {
data_cols[9].hide = true; data_cols[9].hide = true;
@ -174,6 +177,63 @@
} }
}); });
// 监听工具条事件
table.on('tool(currentTableFilter)', function(obj) {
var data = obj.data;
if (obj.event === 'edit') {
// 当前状态取反
var newEnabled = !data.enabled;
layer.confirm('确定要修改状态吗?', {
btn: ['确定', '取消']
}, function(index) {
$.ajax({
url: '/page/gnssUpdateEnabled',
type: 'POST',
data: {
deviceid: data.deviceid,
createtime: data.createtime,
enabled: newEnabled ? 1 : 0
},
success: function(res) {
if (res === 'success') {
layer.msg('修改成功');
// 更新表格数据
table.reload('currentTableId');
} else {
layer.msg('修改失败:' + res);
}
layer.close(index);
},
error: function(xhr) {
layer.msg('操作失败');
layer.close(index);
}
});
});
}
});
// else if (obj.event === 'delete') {
// layer.confirm('确定删除'+data.deviceid+"?", function(index){
// $.ajax({
// type:"POST",
// url:"/gnss/device/delete",
// data:{
// 'del_id':data.deviceid
// },
// success: function (data) {
// //data是cotroller相应处理函数的返回值
// table.reload('currentTableId');
// },
// error: function () {
// console.log("ajax error");
// }
// });
// layer.close(index);
// });
// }
// });
// 监听搜索操作 // 监听搜索操作
form.on('submit(data-search-btn)', function (data) { form.on('submit(data-search-btn)', function (data) {
var result = JSON.stringify(data.field); var result = JSON.stringify(data.field);

View File

@ -30,6 +30,12 @@
<input type="text" name="parentid" autocomplete="off" class="layui-input"> <input type="text" name="parentid" autocomplete="off" class="layui-input">
</div> </div>
</div> </div>
<div class="layui-inline">
<label class="layui-form-label">备选基站号</label>
<div class="layui-input-inline">
<input type="text" name="parentid1" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline"> <div class="layui-inline">
<label class="layui-form-label">项目号</label> <label class="layui-form-label">项目号</label>
<div class="layui-input-inline"> <div class="layui-input-inline">
@ -41,6 +47,7 @@
<div class="layui-input-inline"> <div class="layui-input-inline">
<select name="tenantname" id="tenantname" lay-search=""> <select name="tenantname" id="tenantname" lay-search="">
<option value="">全部</option> <option value="">全部</option>
<option value="非SAAS服务商">非SAAS服务商</option>
<option th:each="item : ${tenant_list}" th:text="${item.name}" th:value="${item.name}"></option> <option th:each="item : ${tenant_list}" th:text="${item.name}" th:value="${item.name}"></option>
</select> </select>
</div> </div>
@ -127,6 +134,7 @@
{field: 'group_id', title: '基本参数组', width: 60, sort: true}, {field: 'group_id', title: '基本参数组', width: 60, sort: true},
{field: 'calc_group_id', title: '解算参数组', width: 60, sort: true}, {field: 'calc_group_id', title: '解算参数组', width: 60, sort: true},
{field: 'parentid', title: '基站编号', width: 80, sort: true}, {field: 'parentid', title: '基站编号', width: 80, sort: true},
{field: 'parentid1', title: '备选基站', width: 80, sort: true},
{field: 'tenantname', title: '所属组织', width: 120}, {field: 'tenantname', title: '所属组织', width: 120},
{field: 'fwd_group_id', title: '推送组', width: 80}, {field: 'fwd_group_id', title: '推送组', width: 80},
{field: 'fwd_group_id2', title: '推送2', width: 80}, {field: 'fwd_group_id2', title: '推送2', width: 80},

View File

@ -54,6 +54,7 @@
{field: 'active_time', title: '激活时长(分钟)'}, {field: 'active_time', title: '激活时长(分钟)'},
{field: 'active_offset', title: '偏置(分钟)'}, {field: 'active_offset', title: '偏置(分钟)'},
{field: 'rs_adv', title: '基准站提前时间(分钟)'}, {field: 'rs_adv', title: '基准站提前时间(分钟)'},
{field: 'gnss_sample_s', title: 'GNSS上报'},
{field: 'power_mode', title: '功耗模式',templet: "<div>{{d.power_mode==0?'低功耗':'普通'}}</div>"}, {field: 'power_mode', title: '功耗模式',templet: "<div>{{d.power_mode==0?'低功耗':'普通'}}</div>"},
{field: 'device_num', title: '关联设备数'}, {field: 'device_num', title: '关联设备数'},
{title: '操作', toolbar: '#currentTableBar', align: "center"} {title: '操作', toolbar: '#currentTableBar', align: "center"}

View File

@ -0,0 +1,278 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SIM卡信息查询</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">
</head>
<body>
<div class="layuimini-container">
<div class="layuimini-main">
<fieldset class="table-search-fieldset">
<legend>搜索信息</legend>
<div style="margin: 10px 10px 10px 10px">
<form class="layui-form layui-form-pane" action="" id="searchForm">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">查询类型</label>
<div class="layui-input-inline">
<select name="searchType" lay-verify="required">
<option value="deviceId">设备号</option>
<option value="iccid">ICCID</option>
<option value="simNumber">SIM卡号</option>
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">搜索内容</label>
<div class="layui-input-inline">
<input type="text" name="searchContent" id="searchInput" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<select name="status">
<option value="">全部</option>
<option value="1">待激活</option>
<option value="2">已激活</option>
<option value="3">停机</option>
<option value="4">注销</option>
<option value="5">库存</option>
<option value="6">可测试</option>
<option value="7">失效</option>
</select>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<button type="submit" class="layui-btn layui-btn-primary" lay-submit lay-filter="searchSubmit"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</div>
</form>
</div>
</fieldset>
<div class="layui-tab layui-tab-card" lay-filter="data-tab">
<ul class="layui-tab-title">
<li class="layui-this">数据表格</li>
<li>流量图表</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<table class="layui-hide" id="simTable" lay-filter="simTableFilter"></table>
</div>
<div class="layui-tab-item">
<div id="trafficChart" style="min-height:300px;padding: 10px"></div>
</div>
</div>
</div>
</div>
</div>
<script src="../js/lay-module/echarts/echartsTheme.js" charset="utf-8"></script>
<script src="../js/lay-module/echarts/echarts.js" charset="utf-8"></script>
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script type="text/html" id="statusTpl">
{{# if(d.status === 1){ }}
<span class="layui-badge layui-bg-orange">待激活</span>
{{# } else if(d.status === 2){ }}
<span class="layui-badge layui-bg-green">已激活</span>
{{# } else if(d.status === 3){ }}
<span class="layui-badge layui-bg-red">停机</span>
{{# } else if(d.status === 4){ }}
<span class="layui-badge layui-bg-black">注销</span>
{{# } else if(d.status === 5){ }}
<span class="layui-badge layui-bg-blue">库存</span>
{{# } else if(d.status === 6){ }}
<span class="layui-badge layui-bg-cyan">可测试</span>
{{# } else if(d.status === 7){ }}
<span class="layui-badge">失效</span>
{{# } }}
</script>
<script th:inline="javascript">
layui.use(['form', 'table','layer','element'], function () {
var table = layui.table
,form = layui.form
,layer = layui.layer
,element = layui.element;
var flowChart;
function initEcharts() {
if (!flowChart) {
flowChart = echarts.init(document.getElementById('trafficChart'), 'theme');
}
}
function updateFlowChart(simData) {
initEcharts();
var used = parseFloat(simData.used) || 0;
var remaining = parseFloat(simData.remaining) || 0;
var total = parseFloat(simData.total) || (used + remaining);
var option = {
title: {
text: 'SIM卡流量使用情况',
left: 'center',
top: 20,
textStyle: {
fontSize: 16
}
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c}MB ({d}%)'
},
legend: {
orient: 'horizontal', // 改为水平布局
bottom: 20, // 放在底部
left: 'center', // 居中对齐
itemWidth: 25,
itemHeight: 14
},
series: [
{
name: '流量使用情况',
type: 'pie',
radius: ['40%', '60%'], // 调整饼图大小
center: ['50%', '50%'], // 居中显示
avoidLabelOverlap: false,
label: {
show: true,
position: 'outside', // 标签位置改为外部
formatter: function(params) {
return params.name + '\n' +
params.value + 'MB\n' +
params.percent + '%';
},
fontSize: 14,
lineHeight: 20
},
labelLine: {
show: true,
length: 15,
length2: 10
},
emphasis: {
label: {
show: true,
fontSize: 16,
fontWeight: 'bold'
}
},
data: [
{
value: used,
name: '已使用流量',
itemStyle: { color: '#FF5722' }
},
{
value: remaining,
name: '剩余流量',
itemStyle: { color: '#009688' }
}
]
}
]
};
document.getElementById('trafficChart').style.height = '400px';
flowChart.setOption(option);
flowChart.resize(); // 重新调整大小
}
var data_cols = [
{field: 'deviceid', title: '设备号'},
{field: 'iccid', title: 'ICCID'},
{field: 'msisdn', title: 'SIM 卡号'},
{field: 'updatetime', title: '更新时间',templet: "<div>{{layui.util.toDateString(d.updatetime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
{field: 'status', title: '状态',templet: '#statusTpl'},
{field: 'remaining', title: '剩余流量(MB)'},
{field: 'used', title: '已使用流量(MB)'},
{field: 'total', title: '总流量(MB)'}
];
form.render();
table.render({
elem: '#simTable',
url: '/sim/list',
toolbar: '#toolbarDemo', //开启头部工具栏
defaultToolbar: ['filter'],
cols: [
data_cols
],
limits: [20, 50, 100, 200, 300],
limit: 20,
page: true,
skin: 'line',
done: function(res) {
if(res.code !== 0) {
layer.msg(res.msg || '查询失败', {icon: 2});
}
}
});
form.verify({
searchContent: function(value, item) {
var type = $('select[name="searchType"]').val();
if(!value) {
return '请输入搜索内容';
}
if(type === 'iccid' && !/^\d{19,20}$/.test(value)) {
return 'ICCID必须是19-20位数字';
}
if(type === 'simNumber' && !/^\d{11,13}$/.test(value)) {
return 'SIM卡号必须是11-13位数字';
}
}
});
form.on('submit(searchSubmit)', function(data){
var loadIndex = layer.load(1);
table.reload('simTable', {
page: {
curr: 1
}
,where: {
searchType: data.field.searchType,
searchContent: data.field.searchContent,
status: data.field.status
}
,done: function(res) {
layer.close(loadIndex);
if(res.code !== 0) {
layer.msg(res.msg || '查询失败', {icon: 2});
} else if(res.count === 0) {
layer.msg('未找到符合条件的数据', {icon: 0});
}else if(res.count === 1) {
// 当查询结果只有一条数据时,使用该数据绘制饼图
updateFlowChart(res.data[0]);
}
}
});
return false;
});
//监听Tab切换重新resize图表否则显示不出来
element.on('tab(data-tab)', function(data){
if(data.index === 1 && flowChart) {
flowChart.resize();
}
});
// 监听窗口大小变化
window.addEventListener('resize', function() {
if (flowChart) {
flowChart.resize();
}
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,290 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SIM卡信息查询</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">
</head>
<body>
<div class="layuimini-container">
<div class="layuimini-main">
<fieldset class="table-search-fieldset">
<legend>SIM卡相关信息聚合查询</legend>
<div style="margin: 10px 10px 10px 10px">
<form class="layui-form layui-form-pane" action="" id="searchForm">
<div class="layui-form-item">
<label class="layui-form-label">搜索类型</label>
<div class="layui-input-inline">
<select id="searchType" name="searchType" lay-search="" lay-filter="searchType">
<option value="iccid">ICCID</option>
<option value="deviceId">设备ID</option>
<option value="simNumber">SIM卡号</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">搜索内容</label>
<div class="layui-input-block">
<input type="text" id="searchInput" name="searchContent" autocomplete="off" placeholder="搜索内容" lay-verify="required" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<button type="button" class="layui-btn" onclick="searchSIM()" lay-submit lay-filter="searchSubmit"><i class="layui-icon">&#xe615;</i>搜索</button>
</div>
</div>
</form>
</div>
</fieldset>
<div id="resultContainer" class="result-container layui-hide">
<div class="layui-card">
<div class="layui-card-body" id="resultContent">
</div>
</div>
</div>
</div>
</div>
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script>
layui.use(['form', 'layer', 'element'], function(){
var form = layui.form;
var layer = layui.layer;
var element = layui.element;
form.render();
form.on('submit(searchSubmit)', function(data){
searchSIM();
return false;
});
});
function searchSIM() {
const searchInput = document.getElementById('searchInput');
const searchContent = searchInput.value.trim();
const searchType = document.querySelector('select[name="searchType"]').value;
if (!searchContent) {
layer.msg('请输入搜索内容');
return;
}
if (searchType === 'iccid' && !/^\d{19,20}$/.test(searchContent)) {
layer.msg('ICCID必须是19-20位数字');
return;
}
if (searchType === 'simNumber' && !/^\d{11,13}$/.test(searchContent)) {
layer.msg('SIM卡号必须是11-13位数字');
return;
}
const loadingIndex = layer.load(1, {
shade: [0.1, '#fff']
});
fetch(`/api/proxy/sim/query?type=${searchType}&content=${searchContent}`)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(result => {
layer.close(loadingIndex);
console.log('API Response:', result);
if (result.Status === 1 && result.Data) {
displayResult(result.Data);
} else {
layer.msg(result.Message || '查询失败');
}
})
.catch(error => {
layer.close(loadingIndex);
console.error('Error:', error);
layer.msg('请求处理失败:' + error.message);
});
}
function displayResult(data) {
const resultContainer = document.getElementById('resultContainer');
const resultContent = document.getElementById('resultContent');
if (!resultContainer || !resultContent) {
console.error('Result container elements not found');
return;
}
resultContainer.classList.remove('layui-hide');
// 格式化状态和其他信息
const statusText = getStatusText(data.status);
const statusClass = getStatusClass(data.status);
const operatorText = getOperatorText(data.operatortype);
// 格式化流量数据
const gprsInfo = {
total: parseFloat(data.gprs?.total) || 0,
used: parseFloat(data.gprs?.used) || 0,
left: parseFloat(data.gprs?.left) || 0
};
const usagePercentage = calculateUsagePercentage(gprsInfo);
resultContent.innerHTML = `
<table class="layui-table">
<tbody>
<tr>
<td width="120">运营商</td>
<td>${operatorText}</td>
</tr>
<tr>
<td>ICCID</td>
<td>${data.iccid || '-'}</td>
</tr>
<tr>
<td>SIM卡号</td>
<td>${data.msisdn || '-'}</td>
</tr>
<tr>
<td>IMSI</td>
<td>${data.imsi || '-'}</td>
</tr>
<tr>
<td>套餐信息</td>
<td>
ID: ${data.packageid || '-'}<br>
名称: ${data.packagename || '-'}
</td>
</tr>
<tr>
<td>时间信息</td>
<td>
激活时间: ${data.activetime || '-'}<br>
有效期: ${data.starttime || '-'} 至 ${data.stoptime || '-'}<br>
沉默期结束: ${data.silentdate || '-'}
</td>
</tr>
<tr>
<td>状态</td>
<td><span class="layui-badge ${statusClass}">${statusText}</span></td>
</tr>
<tr>
<td>APN信息</td>
<td>
${data.apn ? `
<div>ID: ${data.apn.apnid || '-'}</div>
<div>状态: ${data.apn.status === '01' ?
'<span class="layui-badge layui-bg-green">在线</span>' :
'<span class="layui-badge layui-bg-gray">离线</span>'}</div>
<div>IP: ${data.apn.ip || '-'}</div>
<div>网络: ${getNetworkText(data.apn.rat)}</div>
<div>设备状态: ${data.apn.onoffstatus === '1' ?
'<span class="layui-badge layui-bg-green">开机</span>' :
'<span class="layui-badge layui-bg-gray">关机</span>'}</div>
` : '-'}
</td>
</tr>
<tr>
<td>GPRS流量</td>
<td>
<div class="layui-row">
<div class="layui-col-md4">总流量: ${formatFlowSize(gprsInfo.total)} MB</div>
<div class="layui-col-md4">已用: ${formatFlowSize(gprsInfo.used)} MB</div>
<div class="layui-col-md4">剩余: ${formatFlowSize(gprsInfo.left)} MB</div>
</div>
<div class="layui-progress layui-progress-big" style="margin-top: 10px;">
<div class="layui-progress-bar ${getProgressBarColor(gprsInfo)}"
style="width: ${usagePercentage}%">
</div>
</div>
</td>
</tr>
</tbody>
</table>
`;
// 重新渲染进度条
layui.element.render('progress');
}
function getStatusText(status) {
const statusMap = {
1: '待激活',
2: '已激活',
3: '停机',
4: '注销',
5: '库存',
6: '可测试',
7: '失效'
};
return statusMap[status] || '未知状态';
}
function getOperatorText(type) {
const operatorMap = {
1: '中国移动',
2: '中国联通',
3: '中国电信'
};
return operatorMap[type] || '未知运营商';
}
function getNetworkText(rat) {
const networkMap = {
'1': '3G',
'2': '2G',
'6': '4G',
'8': 'NB'
};
return networkMap[rat] || '未知网络';
}
function getStatusClass(status) {
const classMap = {
1: 'layui-bg-orange', // 待激活
2: 'layui-bg-green', // 已激活
3: 'layui-bg-red', // 停机
4: 'layui-bg-gray', // 注销
5: 'layui-bg-blue', // 库存
6: 'layui-bg-cyan', // 可测试
7: 'layui-bg-black' // 失效
};
return classMap[status] || 'layui-bg-gray';
}
function getProgressBarColor(gprsInfo) {
const percentage = calculateUsagePercentage(gprsInfo);
if (percentage >= 90) return 'layui-bg-red';
if (percentage >= 70) return 'layui-bg-orange';
return 'layui-bg-green';
}
function calculateUsagePercentage(gprsInfo) {
// 确保所有值都是数字并且total不为0
const total = parseFloat(gprsInfo.total) || 0;
const used = parseFloat(gprsInfo.used) || 0;
if (total <= 0) return 0;
const percentage = (used / total) * 100;
return Math.min(100, Math.round(percentage));
}
function formatFlowSize(size) {
if (typeof size !== 'number' || isNaN(size)) return '0.00';
return size.toFixed(2);
}
// 按回车键触发查询
document.getElementById('searchInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
e.preventDefault();
searchSIM();
}
});
</script>
</body>
</html>

View File

@ -81,6 +81,12 @@
<input type="number" name="parentid" id="parentid" placeholder="请输入关联基准站编号" value="" class="layui-input"> <input type="number" name="parentid" id="parentid" placeholder="请输入关联基准站编号" value="" class="layui-input">
</div> </div>
</div> </div>
<div class="layui-inline" >
<label class="layui-form-label">备选基站</label>
<div class="layui-input-block">
<input type="number" name="parentid1" id="parentid1" placeholder="请输入备选基准站编号" value="" class="layui-input">
</div>
</div>
</div> </div>
<div class="layui-form-item" id="ecef_div"> <div class="layui-form-item" id="ecef_div">
<div class="layui-inline"> <div class="layui-inline">
@ -207,6 +213,12 @@
</div> </div>
</div> </div>
<hr> <hr>
<div class="layui-form-item" th:if="${role=='SUPER_ADMIN'}">
<label class="layui-form-label">ICCID</label>
<div class="layui-input-block">
<input type="text" name="iccid" id="iccid" class="layui-input" placeholder="请输入19-20位的ICCID号码">
</div>
</div>
<div class="layui-form-item" th:if="${role=='SUPER_ADMIN'}"> <div class="layui-form-item" th:if="${role=='SUPER_ADMIN'}">
<label class="layui-form-label">备注</label> <label class="layui-form-label">备注</label>
<div class="layui-input-block"> <div class="layui-input-block">
@ -301,6 +313,7 @@
$('#name').val(data.name); $('#name').val(data.name);
$('#devicetype').val(data.devicetype); $('#devicetype').val(data.devicetype);
$('#parentid').val(data.parentid); $('#parentid').val(data.parentid);
$('#parentid1').val(data.parentid1);
$('#tenantname').val(data.tenantname); $('#tenantname').val(data.tenantname);
$('#project_id').val(data.project_id); $('#project_id').val(data.project_id);
$('#project2_id').val(data.project2_id); $('#project2_id').val(data.project2_id);
@ -320,6 +333,7 @@
$('#model').val(data.model); $('#model').val(data.model);
$('#sector').val(data.sector); $('#sector').val(data.sector);
$('#remark').val(data.remark); $('#remark').val(data.remark);
$('#iccid').val(data.iccid);
setEcefEditor(); setEcefEditor();
form.render(); form.render();
} }

View File

@ -47,6 +47,12 @@
<input type="number" name="active_offset" id="active_offset" placeholder="请输入配置" value="0" class="layui-input"> <input type="number" name="active_offset" id="active_offset" placeholder="请输入配置" value="0" class="layui-input">
</div> </div>
</div> </div>
<div class="layui-form-item">
<label class="layui-form-label">GNSS上报(秒)</label>
<div class="layui-input-block">
<input type="number" name="gnss_sample_s" id="gnss_sample_s" placeholder="请输入配置" value="0" class="layui-input">
</div>
</div>
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">基准站提前时间(分钟)</label> <label class="layui-form-label">基准站提前时间(分钟)</label>
<div class="layui-input-block"> <div class="layui-input-block">
@ -111,6 +117,7 @@
$('#rs_adv').val(data.rs_adv); $('#rs_adv').val(data.rs_adv);
$('#power_mode').val(data.power_mode); $('#power_mode').val(data.power_mode);
$('#name').val(data.name); $('#name').val(data.name);
$('#gnss_sample_s').val(data.gnss_sample_s);
form.render(); form.render();
} }
</script> </script>

View File

@ -67,13 +67,13 @@ public class BeidouDevice {
executeAsD342("C:\\Users\\wd\\Desktop\\log\\2412254_0424_4xx.log"); executeAsD342("C:\\Users\\wd\\Desktop\\log\\2412254_0424_4xx.log");
executeAsD342("C:\\Users\\wd\\Desktop\\log\\2412254_0424_5xx.log"); executeAsD342("C:\\Users\\wd\\Desktop\\log\\2412254_0424_5xx.log");
*/ */
//execute("C:\\Users\\wd\\Desktop\\log\\2345076_0424_5xx.log"); execute("C:\\Users\\wd\\Desktop\\log\\2345076_0424_5xx.log");
//executeAsD342("C:\\Users\\wd\\Desktop\\log\\b562_2412270_1xx.log"); //executeAsD342("C:\\Users\\wd\\Desktop\\log\\b562_2412270_1xx.log");
//executeAsD342("C:\\Users\\wd\\Desktop\\log\\b562_2412270_2xx.log"); //executeAsD342("C:\\Users\\wd\\Desktop\\log\\b562_2412270_2xx.log");
//execute("C:\\Users\\wd\\Desktop\\log\\2345076_0424_1.log"); /* executeAsD342("C:\\Users\\wd\\Desktop\\log\\2345076_0424_1.log");
execute("C:\\Users\\wd\\Desktop\\log\\2345076_0424_2.log"); executeAsD342("C:\\Users\\wd\\Desktop\\log\\2345076_0424_2.log");
/*executeAsD342("C:\\Users\\wd\\Desktop\\log\\2345076_0424_1xx.log"); executeAsD342("C:\\Users\\wd\\Desktop\\log\\2345076_0424_1xx.log");
executeAsD342("C:\\Users\\wd\\Desktop\\log\\2345076_0424_2xx.log"); executeAsD342("C:\\Users\\wd\\Desktop\\log\\2345076_0424_2xx.log");
executeAsD342("C:\\Users\\wd\\Desktop\\log\\2345076_0424_3xx.log"); executeAsD342("C:\\Users\\wd\\Desktop\\log\\2345076_0424_3xx.log");
executeAsD342("C:\\Users\\wd\\Desktop\\log\\2345076_0424_4xx.log"); executeAsD342("C:\\Users\\wd\\Desktop\\log\\2345076_0424_4xx.log");
@ -120,12 +120,7 @@ public class BeidouDevice {
cycleCount++; cycleCount++;
} }
if(arrs[2].startsWith("d3f2")){
b562Count = b562Count;
}
else{
udpClient.sendData(ByteUtil.hexStringTobyte(arrs[2])); udpClient.sendData(ByteUtil.hexStringTobyte(arrs[2]));
}
b562Count++; b562Count++;
lastTime = time.getTime(); lastTime = time.getTime();
Thread.sleep(100); Thread.sleep(100);