From 43012077ca5b4869fa82ce155bf01d08adceda3e Mon Sep 17 00:00:00 2001
From: wyc <1104749580@qq.com>
Date: Tue, 16 Jun 2026 11:04:03 +0800
Subject: [PATCH] =?UTF-8?q?=E9=A6=96=E6=AC=A1=E6=8F=90=E4=BA=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/.gitignore | 8 +
.idea/editor.xml | 252 ++
.idea/misc.xml | 6 +
.idea/mode-s.iml | 8 +
.idea/modules.xml | 8 +
CMakeLists.txt | 0
SSR/ACAS/ACAS.cpp | 2 +
SSR/ACAS/ACAS.h | 24 +
SSR/ACAS/ACAS.hpp | 407 +++
SSR/ACAS/ACAS_9_56.hpp | 62 +
SSR/ADS_B/ADS_B.cpp | 4 +
SSR/ADS_B/ADS_B.h | 44 +
SSR/ADS_B/ADS_B.hpp | 891 +++++++
SSR/Aircraft_Info.cpp | 561 ++++
SSR/Aircraft_Info.h | 311 +++
SSR/CPR/CPR.cpp | 379 +++
SSR/CPR/CPR.h | 140 +
SSR/CPR/CPR_TEST.cpp | 189 ++
SSR/CPR/Earth.h | 159 ++
SSR/Commb/Commb.cpp | 2 +
SSR/Commb/Commb.h | 57 +
SSR/Commb/Commb.hpp | 836 ++++++
SSR/HPP.h | 5 +
SSR/ICAO_9871_2012/1090.hpp | 6 +
SSR/ICAO_9871_2012/GLOSSARY.h | 9 +
SSR/Mode_S/Mode_S.cpp | 19 +
SSR/Mode_S/Mode_S.h | 71 +
SSR/Mode_S/Mode_S.hpp | 96 +
SSR/Msg.cpp | 1 +
SSR/Msg.h | 307 +++
SSR/convert/DataOutputFormats.cpp | 111 +
SSR/convert/DataOutputFormats.h | 532 ++++
SSR/convert/HULC.h | 5 +
SSR/convert/KML_output.cpp | 5 +
SSR/convert/KML_output.h | 12 +
SSR/convert/SBS.cpp | 123 +
SSR/convert/SBS.h | 168 ++
SSR/convert/base_format.h | 56 +
SSR/enum.cpp | 161 ++
SSR/enum.h | 307 +++
SSR/export.cpp | 11 +
SSR/export.h | 62 +
SSR/export.hpp | 20 +
SSR/export_type.h | 30 +
SSR/global.h | 495 ++++
SSR/py_Mode_S/Common.cpp | 1131 ++++++++
SSR/py_Mode_S/Common.h | 363 +++
SSR/py_Mode_S/LICENSE | 674 +++++
SSR/py_Mode_S/acas.cpp | 5 +
SSR/py_Mode_S/ads_b.cpp | 146 ++
SSR/py_Mode_S/allcall.cpp | 44 +
SSR/py_Mode_S/bds.cpp | 2241 ++++++++++++++++
SSR/py_Mode_S/commb.cpp | 25 +
SSR/py_Mode_S/ehs.cpp | 10 +
SSR/py_Mode_S/els.cpp | 10 +
SSR/py_Mode_S/surv.cpp | 2 +
SSR/py_Mode_S/uncertainty.cpp | 0
SSR/py_Mode_S/uplink.cpp | 0
SSR/uncertainty.h | 157 ++
main.cmake | 16 +
pyModeS/LICENSE | 674 +++++
readsb/comm_b.cpp | 962 +++++++
readsb/comm_b.h | 293 +++
readsb2/ais_charset.cpp | 26 +
readsb2/ais_charset.h | 29 +
readsb2/comm_b.cpp | 962 +++++++
readsb2/comm_b.h | 31 +
readsb2/cpr.cpp | 374 +++
readsb2/cpr.h | 43 +
readsb2/crc.cpp | 566 ++++
readsb2/crc.h | 46 +
readsb2/icao_filter.cpp | 154 ++
readsb2/icao_filter.h | 48 +
readsb2/mode_ac.cpp | 205 ++
readsb2/mode_s.cpp | 2251 ++++++++++++++++
readsb2/mode_s.h | 128 +
readsb2/readsb.h | 1355 ++++++++++
readsb2/track.cpp | 3994 +++++++++++++++++++++++++++++
readsb2/track.h | 796 ++++++
test/full_test_adsb.h | 103 +
test/global.h | 14 +
test/main2.cpp | 44 +
test/test_adsb.h | 263 ++
test/test_allcall.h | 59 +
test/test_bds_inference.h | 62 +
test/test_c_common.h | 101 +
test/test_mode_a_c.h | 45 +
test/test_surv.h | 90 +
test/test_tell.h | 66 +
89 files changed, 25570 insertions(+)
create mode 100644 .idea/.gitignore
create mode 100644 .idea/editor.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/mode-s.iml
create mode 100644 .idea/modules.xml
create mode 100644 CMakeLists.txt
create mode 100644 SSR/ACAS/ACAS.cpp
create mode 100644 SSR/ACAS/ACAS.h
create mode 100644 SSR/ACAS/ACAS.hpp
create mode 100644 SSR/ACAS/ACAS_9_56.hpp
create mode 100644 SSR/ADS_B/ADS_B.cpp
create mode 100644 SSR/ADS_B/ADS_B.h
create mode 100644 SSR/ADS_B/ADS_B.hpp
create mode 100644 SSR/Aircraft_Info.cpp
create mode 100644 SSR/Aircraft_Info.h
create mode 100644 SSR/CPR/CPR.cpp
create mode 100644 SSR/CPR/CPR.h
create mode 100644 SSR/CPR/CPR_TEST.cpp
create mode 100644 SSR/CPR/Earth.h
create mode 100644 SSR/Commb/Commb.cpp
create mode 100644 SSR/Commb/Commb.h
create mode 100644 SSR/Commb/Commb.hpp
create mode 100644 SSR/HPP.h
create mode 100644 SSR/ICAO_9871_2012/1090.hpp
create mode 100644 SSR/ICAO_9871_2012/GLOSSARY.h
create mode 100644 SSR/Mode_S/Mode_S.cpp
create mode 100644 SSR/Mode_S/Mode_S.h
create mode 100644 SSR/Mode_S/Mode_S.hpp
create mode 100644 SSR/Msg.cpp
create mode 100644 SSR/Msg.h
create mode 100644 SSR/convert/DataOutputFormats.cpp
create mode 100644 SSR/convert/DataOutputFormats.h
create mode 100644 SSR/convert/HULC.h
create mode 100644 SSR/convert/KML_output.cpp
create mode 100644 SSR/convert/KML_output.h
create mode 100644 SSR/convert/SBS.cpp
create mode 100644 SSR/convert/SBS.h
create mode 100644 SSR/convert/base_format.h
create mode 100644 SSR/enum.cpp
create mode 100644 SSR/enum.h
create mode 100644 SSR/export.cpp
create mode 100644 SSR/export.h
create mode 100644 SSR/export.hpp
create mode 100644 SSR/export_type.h
create mode 100644 SSR/global.h
create mode 100644 SSR/py_Mode_S/Common.cpp
create mode 100644 SSR/py_Mode_S/Common.h
create mode 100644 SSR/py_Mode_S/LICENSE
create mode 100644 SSR/py_Mode_S/acas.cpp
create mode 100644 SSR/py_Mode_S/ads_b.cpp
create mode 100644 SSR/py_Mode_S/allcall.cpp
create mode 100644 SSR/py_Mode_S/bds.cpp
create mode 100644 SSR/py_Mode_S/commb.cpp
create mode 100644 SSR/py_Mode_S/ehs.cpp
create mode 100644 SSR/py_Mode_S/els.cpp
create mode 100644 SSR/py_Mode_S/surv.cpp
create mode 100644 SSR/py_Mode_S/uncertainty.cpp
create mode 100644 SSR/py_Mode_S/uplink.cpp
create mode 100644 SSR/uncertainty.h
create mode 100644 main.cmake
create mode 100644 pyModeS/LICENSE
create mode 100644 readsb/comm_b.cpp
create mode 100644 readsb/comm_b.h
create mode 100644 readsb2/ais_charset.cpp
create mode 100644 readsb2/ais_charset.h
create mode 100644 readsb2/comm_b.cpp
create mode 100644 readsb2/comm_b.h
create mode 100644 readsb2/cpr.cpp
create mode 100644 readsb2/cpr.h
create mode 100644 readsb2/crc.cpp
create mode 100644 readsb2/crc.h
create mode 100644 readsb2/icao_filter.cpp
create mode 100644 readsb2/icao_filter.h
create mode 100644 readsb2/mode_ac.cpp
create mode 100644 readsb2/mode_s.cpp
create mode 100644 readsb2/mode_s.h
create mode 100644 readsb2/readsb.h
create mode 100644 readsb2/track.cpp
create mode 100644 readsb2/track.h
create mode 100644 test/full_test_adsb.h
create mode 100644 test/global.h
create mode 100644 test/main2.cpp
create mode 100644 test/test_adsb.h
create mode 100644 test/test_allcall.h
create mode 100644 test/test_bds_inference.h
create mode 100644 test/test_c_common.h
create mode 100644 test/test_mode_a_c.h
create mode 100644 test/test_surv.h
create mode 100644 test/test_tell.h
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..35410ca
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/editor.xml b/.idea/editor.xml
new file mode 100644
index 0000000..510869e
--- /dev/null
+++ b/.idea/editor.xml
@@ -0,0 +1,252 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..369389b
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/mode-s.iml b/.idea/mode-s.iml
new file mode 100644
index 0000000..bc2cd87
--- /dev/null
+++ b/.idea/mode-s.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..7c3556b
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/SSR/ACAS/ACAS.cpp b/SSR/ACAS/ACAS.cpp
new file mode 100644
index 0000000..0d0343c
--- /dev/null
+++ b/SSR/ACAS/ACAS.cpp
@@ -0,0 +1,2 @@
+#include "ACAS.h"
+
diff --git a/SSR/ACAS/ACAS.h b/SSR/ACAS/ACAS.h
new file mode 100644
index 0000000..98e7de2
--- /dev/null
+++ b/SSR/ACAS/ACAS.h
@@ -0,0 +1,24 @@
+#pragma once
+#include "ACAS.hpp"
+namespace SSR::ACAS {
+ // 这些是监视询问 是发送给飞机的
+ template
+ using SI = ACAS_T::Surveillance_Interrogation_112;
+ ADD_56_1(Short_Surveillance_Interrogation, ACAS_T::Surveillance_Interrogation_56)
+ ADD_112_2(Surveillance_Interrogation30, SI, ACAS_T::UDS_3_0_Coordination_Interrogation)
+ ADD_112_2(Surveillance_Interrogation31, SI, ACAS_T::UDS_3_1_Coordination_Interrogation)
+ ADD_112_3(Surveillance_Interrogation31_1, SI,
+ ACAS_T::UDS_3_1_Coordination_Interrogation, ACAS_T::UDS_3_1_ARA1)
+ ADD_112_3(Surveillance_Interrogation31_2, SI,
+ ACAS_T::UDS_3_1_Coordination_Interrogation, ACAS_T::UDS_3_1_ARA2)
+ ADD_112_2(Surveillance_Interrogation32, SI, ACAS_T::UDS_3_2_Coordination_Interrogation)
+
+ // 询问恢复
+ ADD_56_1(Short_Reply, ACAS_T::Reply_56)
+ ADD_112_2(Reply_3_0, ACAS_T::Reply_112, ACAS_T::VDS_3_0_Coordination_Reply)
+ ADD_112_3(Reply_3_0_1, ACAS_T::Reply_112, ACAS_T::VDS_3_0_Coordination_Reply, ACAS_T::VDS_3_0_ARA1)
+ ADD_112_3(Reply_3_0_2, ACAS_T::Reply_112, ACAS_T::VDS_3_0_Coordination_Reply, ACAS_T::VDS_3_0_ARA2)
+ // 剩余的VDS 由 Commb回复
+}
+
+
diff --git a/SSR/ACAS/ACAS.hpp b/SSR/ACAS/ACAS.hpp
new file mode 100644
index 0000000..15c4fe4
--- /dev/null
+++ b/SSR/ACAS/ACAS.hpp
@@ -0,0 +1,407 @@
+#ifndef ACAS_HPP_H
+#define ACAS_HPP_H
+#include "../Mode_S/Mode_S.hpp"
+namespace SSR::ACAS_T {
+
+ template
+ struct Surveillance_Interrogation_56 : with_AP, BDS_ {
+ PROP_T(std::string, icao, "01ABCD")
+ PROP_T(Uplink_Format, uf, Uplink_Format::Short_Air_Air_Surveillance_0)
+ PROP_Bit_T(1, RL, 0) // 应答长度 (RL):1 位,它定义了所需的应答格式:0 需要 DF=0 的应答,而 1 需要 DF=16 的应答
+ PROP_Bit_T(1, AQ, 0) // 它包含控制应答中 RI 字段内容的代码
+ PROP_Bit_T(8, BDS, 0) // 8 位,表示 DF=16 响应的 MV 内容的 BDS 码
+ void set(std::string& msg_bin) {
+ set_bin<0, 5>(msg_bin, static_cast(uf));
+ set_bin<8, 1>(msg_bin, RL);
+ set_bin<13, 1>(msg_bin, AQ);
+ set_bin<14, 8>(msg_bin, BDS);
+ }
+ void parse(std::string& msg_bin) {
+ icao = SSR::decode_icao(msg_bin);
+ uf = static_cast(get_bin<0, 5>(msg_bin));
+ RL = get_bin<8, 1>(msg_bin);
+ AQ = get_bin<13, 1>(msg_bin);
+ BDS = get_bin<14, 8>(msg_bin);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(icao)
+ Ret_J(uf)
+ Ret_J(RL)
+ Ret_J(AQ)
+ Ret_J(BDS)
+ return ret;
+ }
+ };
+ //T_Parser(Surveillance_Interrogation_56)
+
+ template
+ struct Reply_56 : with_AP, BDS_ {
+ PROP_T(std::string, icao, "01ABCD")
+ PROP_T(Downlink_Format, df, Downlink_Format::Short_Air_Air_Surveillance_0)
+ PROP_T(ACAS::Vertical_Status, vertical_status, ACAS::Vertical_Status::Airborne)
+ PROP_T(ACAS::CrossLink_Capability, Cross_link_capability, ACAS::CrossLink_Capability::NotSupported) // 是指在 UF=0 请求时应答 DF=16 的能力。当此 1 位字段设置为 1 时,支持交叉链接。否则,该字段将设置为 0。
+ PROP_Bit_T(3, sensitivity_level, 0) // 灵敏度等级 (SL):3 位,它代表 ACAS 系统的灵敏度等级,但 0 表示 ACAS 不工作。
+ PROP_T(ACAS::Reply_Information, ri, ACAS::Reply_Information::NoACASOperation) //回复ACAS类型
+ PROP_Bit_T(13, altitude_code, 0)
+ void set(std::string& msg_bin) {
+ set_bin<0, 5>(msg_bin, static_cast(df));
+ set_bin<5, 1>(msg_bin, static_cast(vertical_status));
+ set_bin<8, 3>(msg_bin, static_cast(sensitivity_level));
+ set_bin<13, 4>(msg_bin, static_cast(ri));
+ set_bin<19, 13>(msg_bin, altitude_code);
+ }
+ void parse(std::string& msg_bin) {
+ icao = SSR::decode_icao(msg_bin);
+ get_bin<0, 5, Downlink_Format>(msg_bin, df);
+ get_bin<5, 1, ACAS::Vertical_Status>(msg_bin, vertical_status);
+ get_bin<8, 3>(msg_bin, sensitivity_level);
+ get_bin<13, 4, ACAS::Reply_Information>(msg_bin, ri);
+ get_bin<19, 13>(msg_bin, altitude_code);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(icao)
+ Ret_J(df)
+ Ret_J(vertical_status)
+ Ret_J(sensitivity_level)
+ Ret_J(ri)
+ Ret_J(altitude_code)
+ return ret;
+ }
+ };
+ T_Parser(Reply_56)
+
+ template
+ struct Surveillance_Interrogation_112 : with_AP, BDS_ {
+ PROP_T(std::string, icao, "01ABCD")
+ PROP_T(Uplink_Format, uf, Uplink_Format::Long_Air_Air_Surveillance_16)
+ PROP_Bit_T(1, RL, 0) // 应答长度 (RL):1 位,它定义了所需的应答格式:0 需要 DF=0 的应答,而 1 需要 DF=16 的应答
+ PROP_Bit_T(1, AQ, 0) // 它包含控制应答中 RI 字段内容的代码
+ void set(std::string& msg_bin) {
+ set_bin<0, 5>(msg_bin, static_cast(uf));
+ set_bin<8, 1>(msg_bin, static_cast(RL));
+ set_bin<13, 1>(msg_bin, static_cast(AQ));
+ }
+ void parse(std::string& msg_bin) {
+ icao = SSR::decode_icao(msg_bin);
+ get_bin<0, 5, Uplink_Format>(msg_bin, uf);
+ get_bin<8, 1>(msg_bin, RL);
+ get_bin<13, 1>(msg_bin, AQ);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(icao)
+ Ret_J(uf)
+ Ret_J(RL)
+ Ret_J(AQ)
+ return ret;
+ }
+ };
+ //T_Parser(Surveillance_Interrogation_112)
+
+ template
+ struct Reply_112 : with_AP, BDS_ {
+ PROP_T(std::string, icao, "01ABCD")
+ PROP_T(Downlink_Format, df, Downlink_Format::Long_Air_Air_Surveillance_16)
+ PROP_T(ACAS::Vertical_Status, vertical_status, ACAS::Vertical_Status::Airborne)
+ PROP_Bit_T(3, sensitivity_level, 0) // 灵敏度等级 (SL):3 位,它代表 ACAS 系统的灵敏度等级,但 0 表示 ACAS 不工作。
+ PROP_T(ACAS::Reply_Information, ri, ACAS::Reply_Information::NoACASOperation) //回复ACAS类型
+ PROP_Bit_T(13, altitude_code, 0)
+ void set(std::string& msg_bin) {
+ set_bin<0, 5>(msg_bin, static_cast(df));
+ set_bin<5, 1>(msg_bin, static_cast(vertical_status));
+ set_bin<8, 3>(msg_bin, static_cast(sensitivity_level));
+ set_bin<13, 4>(msg_bin, static_cast(ri));
+ set_bin<19, 13>(msg_bin, altitude_code);
+ }
+ void parse(std::string& msg_bin) {
+ icao = SSR::decode_icao(msg_bin);
+ get_bin<0, 5, Downlink_Format>(msg_bin, df);
+ get_bin<5, 1, ACAS::Vertical_Status>(msg_bin, vertical_status);
+ get_bin<8, 3>(msg_bin, sensitivity_level);
+ get_bin<13, 4, ACAS::Reply_Information>(msg_bin, ri);
+ get_bin<19, 13>(msg_bin, altitude_code);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(icao)
+ Ret_J(df)
+ Ret_J(vertical_status)
+ Ret_J(sensitivity_level)
+ Ret_J(ri)
+ Ret_J(altitude_code)
+ return ret;
+ }
+ };
+ T_Parser(Reply_112)
+
+ template
+ struct UDS_3_0_Coordination_Interrogation {
+ static bool is(std::string& msg_bin) {
+ return get_bin<32, 4>(msg_bin) == 3 && get_bin<36, 4>(msg_bin) == 0;
+ }
+ PROP_Bit_T(1, multiple_threat, 0) //多重威胁位 (MTB):1 位,表示是否存在多重威胁。
+ PROP_T(ACAS::Cancel_Vertical_RAC, cancel_vertical_RAC, ACAS::Cancel_Vertical_RAC::NoCancellation)
+ PROP_T(ACAS::Vertical_RAC, vertical_RAC, ACAS::Vertical_RAC::NoInformation)
+ PROP_T(ACAS::Cancel_Horizontal_RAC, cancel_horizontal_RAC, ACAS::Cancel_Horizontal_RAC::NoCancellation)
+ PROP_T(ACAS::Horizontal_RAC, horizontal_RAC, ACAS::Horizontal_RAC::NoInformation)
+ // 水平感应位 (HSB):5 位,使用汉明码和一个额外的奇偶校验位来检测 CHC 和 HRC 字段中的错误(最多 3 位)。
+ PROP_Bit_T(5, HSB, 0)
+ // 垂直感应位 (VSB):4 位,使用汉明码和一个额外的奇偶校验位来检测 CVC 和 VRC 字段中的错误(最多 3 位)。
+ PROP_Bit_T(5, VSB, 0)
+ // 飞机地址 (MID):24 位,包含查询 ACAS 飞机的 24 位飞机应答器地址。
+ PROP_Bit_T(24, aircraft_address, 0)
+ void set(std::string& msg_bin) {
+ set_bin<32, 4>(msg_bin, 3);
+ set_bin<36, 4>(msg_bin, 0);
+ set_bin<41, 1>(msg_bin, multiple_threat);
+ set_bin<42, 2>(msg_bin, static_cast(cancel_vertical_RAC));
+ set_bin<44, 2>(msg_bin, static_cast(vertical_RAC));
+ set_bin<46, 3>(msg_bin, static_cast(cancel_horizontal_RAC));
+ set_bin<49, 3>(msg_bin, static_cast(horizontal_RAC));
+ set_bin<55, 5>(msg_bin, HSB);
+ set_bin<60, 4>(msg_bin, VSB);
+ set_bin<64, 24>(msg_bin, aircraft_address);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<41, 1>(msg_bin, multiple_threat);
+ get_bin<42, 2, ACAS::Cancel_Vertical_RAC>(msg_bin, cancel_vertical_RAC);
+ get_bin<44, 2, ACAS::Vertical_RAC>(msg_bin, vertical_RAC);
+ get_bin<46, 3, ACAS::Cancel_Horizontal_RAC>(msg_bin, cancel_horizontal_RAC);
+ get_bin<49, 3, ACAS::Horizontal_RAC>(msg_bin, horizontal_RAC);
+ get_bin<55, 5>(msg_bin, HSB);
+ get_bin<60, 4>(msg_bin, VSB);
+ get_bin<64, 24>(msg_bin, aircraft_address);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(multiple_threat)
+ Ret_J(cancel_vertical_RAC)
+ Ret_J(vertical_RAC)
+ Ret_J(cancel_horizontal_RAC)
+ Ret_J(horizontal_RAC)
+ Ret_J(HSB)
+ Ret_J(VSB)
+ Ret_J(aircraft_address)
+ return ret;
+ }
+ };
+ //T_Parser(UDS_3_0_Coordination_Interrogation)
+
+ // 表明多个或一个威胁
+ // 当 ARA 第一位(MSG 位 41)为 1 且 MTE 为 0 或 1 时:
+ template
+ struct UDS_3_1_ARA1 {
+ PROP_Bit_T(1, MTE, 0) // 设为1多个威胁 设为0一个威胁
+ PROP_Bit_T(1, corrective_preventive, 0) // Bit 42: RA is corrective (1) or preventive (0)
+ PROP_Bit_T(1, downward_upward, 0) // Bit 43: RA is downward sense (1) or upward sense (0)
+ PROP_Bit_T(1, increased_rate, 0) // Bit 44: RA is increased rate (1) or not (0)
+ PROP_Bit_T(1, sense_reversal, 0) // Bit 45: RA is a sense reversal (1) or not (0)
+ PROP_Bit_T(1, altitude_crossing, 0) // Bit 46: RA is altitude crossing (1) or not (0)
+ PROP_Bit_T(1, positive_vertical_speed_limit, 0) //Bit 47: RA is positive (1) or vertical speed limit (0)
+ static bool is(std::string& msg_bin) {
+ return get_bin<40, 1>(msg_bin) == 1;
+ }
+ void set(std::string& msg_bin) {
+ set_bin<40, 1>(msg_bin, 1);
+ set_bin<59, 1>(msg_bin, MTE);
+ set_bin<41, 1>(msg_bin, corrective_preventive);
+ set_bin<42, 1>(msg_bin, downward_upward);
+ set_bin<43, 1>(msg_bin, increased_rate);
+ set_bin<44, 1>(msg_bin, sense_reversal);
+ set_bin<45, 1>(msg_bin, altitude_crossing);
+ set_bin<46, 1>(msg_bin, positive_vertical_speed_limit);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<59, 1>(msg_bin, MTE);
+ get_bin<41, 1>(msg_bin, corrective_preventive);
+ get_bin<42, 1>(msg_bin, downward_upward);
+ get_bin<43, 1>(msg_bin, increased_rate);
+ get_bin<44, 1>(msg_bin, sense_reversal);
+ get_bin<45, 1>(msg_bin, altitude_crossing);
+ get_bin<46, 1>(msg_bin, positive_vertical_speed_limit);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(corrective_preventive)
+ Ret_J(downward_upward)
+ Ret_J(increased_rate)
+ Ret_J(sense_reversal)
+ Ret_J(altitude_crossing)
+ Ret_J(positive_vertical_speed_limit)
+ return ret;
+ }
+ };
+ //T_Parser(UDS_3_1_ARA1)
+
+
+
+
+ // 当 ARA 第一位(MSG 位 41)为 0 且 MTE 为 1 时:
+ template
+ struct UDS_3_1_ARA2 {
+ PROP_Bit_T(1, upward_correction, 0)//Bit 42: RA requires a correction in the upward sense (1) or not (0)
+ PROP_Bit_T(1, climb, 0)//Bit 43: RA requires a positive climb (1) or not (0)
+ PROP_Bit_T(1, downward_correction, 0)//Bit 44: RA requires a correction in the downward sense (1) or not (0)
+ PROP_Bit_T(1, descent, 0)//Bit 45: RA requires a positive descent (1) or not (0)
+ PROP_Bit_T(1, crossing, 0)//Bit 46: RA requires a crossing (1) or not (0)
+ PROP_Bit_T(1, reversal, 0)//Bit 47: RA is a sense reversal (1) or not (0)
+ static bool is(std::string& msg_bin) {
+ return get_bin<40, 1>(msg_bin) == 0 && get_bin<59, 1>(msg_bin) == 1;
+ }
+ void set(std::string& msg_bin) {
+ set_bin<40, 1>(msg_bin, 0);
+ set_bin<59, 1>(msg_bin, 1); //MTE
+ set_bin<41, 1>(msg_bin, upward_correction);
+ set_bin<42, 1>(msg_bin, climb);
+ set_bin<43, 1>(msg_bin, downward_correction);
+ set_bin<44, 1>(msg_bin, descent);
+ set_bin<45, 1>(msg_bin, crossing);
+ set_bin<46, 1>(msg_bin, reversal);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<41, 1>(msg_bin, upward_correction);
+ get_bin<42, 1>(msg_bin, climb);
+ get_bin<43, 1>(msg_bin, downward_correction);
+ get_bin<44, 1>(msg_bin, descent);
+ get_bin<45, 1>(msg_bin, crossing);
+ get_bin<46, 1>(msg_bin, reversal);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(upward_correction);
+ Ret_J(climb);
+ Ret_J(downward_correction);
+ Ret_J(descent);
+ Ret_J(crossing);
+ Ret_J(reversal);
+ return ret;
+ }
+ };
+ //T_Parser(UDS_3_1_ARA2)
+ // 当 ARA 第一位(MSG 位 41)为 0 且 MTE 为 0 时,不会生成垂直 RA。
+
+ template
+ struct UDS_3_1_Coordination_Interrogation {
+ PROP_Bit_T(1, Do_not_pass_below, 0)
+ PROP_Bit_T(1, Do_not_pass_above, 0)
+ PROP_Bit_T(1, Do_not_pass_left, 0)
+ PROP_Bit_T(1, Do_not_pass_right, 0)
+ PROP_Bit_T(1, RA_terminated_indicator, 0)
+ PROP_Bit_T(13, Mode_A_identity_code, 0)
+ PROP_Bit_T(13, Mode_C_altitude_code, 0)
+ static bool is(std::string& msg_bin) {
+ return get_bin<32, 4>(msg_bin) == 3 && get_bin<36, 4>(msg_bin) == 1;
+ }
+ void set(std::string& msg_bin) {
+ set_bin<32, 4>(msg_bin, 3);
+ set_bin<36, 4>(msg_bin, 1);
+ set_bin<54, 1>(msg_bin, Do_not_pass_below);
+ set_bin<55, 1>(msg_bin, Do_not_pass_above);
+ set_bin<56, 1>(msg_bin, Do_not_pass_left);
+ set_bin<57, 1>(msg_bin, Do_not_pass_right);
+ set_bin<58, 1>(msg_bin, RA_terminated_indicator);
+ set_bin<62, 13>(msg_bin, Mode_A_identity_code);
+ set_bin<75, 13>(msg_bin, Mode_C_altitude_code);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<54, 1>(msg_bin, Do_not_pass_below);
+ get_bin<55, 1>(msg_bin, Do_not_pass_above);
+ get_bin<56, 1>(msg_bin, Do_not_pass_left);
+ get_bin<57, 1>(msg_bin, Do_not_pass_right);
+ get_bin<58, 1>(msg_bin, RA_terminated_indicator);
+ get_bin<62, 13>(msg_bin, Mode_A_identity_code);
+ get_bin<75, 13>(msg_bin, Mode_C_altitude_code);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(Do_not_pass_below)
+ Ret_J(Do_not_pass_above)
+ Ret_J(Do_not_pass_left)
+ Ret_J(Do_not_pass_right)
+ Ret_J(RA_terminated_indicator)
+ Ret_J(Mode_A_identity_code)
+ Ret_J(Mode_C_altitude_code)
+ return ret;
+ }
+ };
+ //T_Parser(UDS_3_1_Coordination_Interrogation)
+
+
+ template
+ struct UDS_3_2_Coordination_Interrogation {
+ PROP_Bit_T(4, U_definition_subfield_1, 0)
+ PROP_Bit_T(4, U_definition_subfield_2, 0)
+ PROP_Bit_T(24, Aircraft_address, 0)
+ void set(std::string& msg_bin) {
+ set_bin<32, 4>(msg_bin, U_definition_subfield_1);
+ set_bin<36, 4>(msg_bin, U_definition_subfield_2);
+ set_bin<64, 24>(msg_bin, Aircraft_address);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<32, 4>(msg_bin, U_definition_subfield_1);
+ get_bin<36, 4>(msg_bin, U_definition_subfield_2);
+ get_bin<64, 24>(msg_bin, Aircraft_address);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(U_definition_subfield_1)
+ Ret_J(U_definition_subfield_2)
+ Ret_J(Aircraft_address)
+ return ret;
+ }
+ };
+ //T_Parser(UDS_3_2_Coordination_Interrogation)
+
+
+ template
+ struct VDS_3_0_ARA1 : UDS_3_1_ARA1 {};
+ T_Parser(VDS_3_0_ARA1)
+
+ template
+ struct VDS_3_0_ARA2 : UDS_3_1_ARA2 {};
+ T_Parser(VDS_3_0_ARA2)
+
+
+
+ template
+ struct VDS_3_0_Coordination_Reply {
+ PROP_Bit_T(1, Do_not_pass_below, 0)
+ PROP_Bit_T(1, Do_not_pass_above, 0)
+ PROP_Bit_T(1, Do_not_pass_left, 0)
+ PROP_Bit_T(1, Do_not_pass_right, 0)
+ PROP_Bit_T(1, RA_terminated_indicator, 0)
+ static bool is(std::string& msg_bin) {
+ return get_bin<32, 4>(msg_bin) == 3 && get_bin<36, 4>(msg_bin) == 0;
+ }
+ void set(std::string& msg_bin) {
+ set_bin<32, 4>(msg_bin, 3);
+ set_bin<36, 4>(msg_bin, 0);
+ set_bin<54, 1>(msg_bin, Do_not_pass_below);
+ set_bin<55, 1>(msg_bin, Do_not_pass_above);
+ set_bin<56, 1>(msg_bin, Do_not_pass_left);
+ set_bin<57, 1>(msg_bin, Do_not_pass_right);
+ set_bin<58, 1>(msg_bin, RA_terminated_indicator);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<54, 1>(msg_bin, Do_not_pass_below);
+ get_bin<55, 1>(msg_bin, Do_not_pass_above);
+ get_bin<56, 1>(msg_bin, Do_not_pass_left);
+ get_bin<57, 1>(msg_bin, Do_not_pass_right);
+ get_bin<58, 1>(msg_bin, RA_terminated_indicator);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(Do_not_pass_below)
+ Ret_J(Do_not_pass_above)
+ Ret_J(Do_not_pass_left)
+ Ret_J(Do_not_pass_right)
+ Ret_J(RA_terminated_indicator)
+ return ret;
+ }
+ };
+ T_Parser(VDS_3_0_Coordination_Reply)
+}
+
+#endif
diff --git a/SSR/ACAS/ACAS_9_56.hpp b/SSR/ACAS/ACAS_9_56.hpp
new file mode 100644
index 0000000..7496b3d
--- /dev/null
+++ b/SSR/ACAS/ACAS_9_56.hpp
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "../Mode_S/Mode_S.h"
+
+namespace SSR {
+// common b adsb 都有用到
+template
+struct ACAS_Active_Resolution_Advisory_9_56{
+ // resolution advisory complements (RAC)
+ PROP_Bit_T(1, Do_not_pass_below, 0)
+ PROP_Bit_T(1, Do_not_pass_above, 0)
+ PROP_Bit_T(1, Do_not_turn_left, 0)
+ PROP_Bit_T(1, Do_not_turn_right, 0)
+ PROP_Bit_T(1, RA_terminated, 0) //RA终止位指示先前生成的RA是否已终止。
+ PROP_T(Threat_Type_Indicator, threat_Type_Indicator, Threat_Type_Indicator::No_Identity_Data)
+ PROP_Bit_T(26, threat_data, 0)
+
+ ACAS_SubType parse_sum(std::string& msg_bin) {
+ int m9 = get_bin<32 + 9, 1>(msg_bin);
+ int m28 = get_bin<32 + 28, 1>(msg_bin);
+ if (m9 == 0 && m28 == 0) return ACAS_SubType::NO_RA;
+ if (m9 == 0 && m28 == 1) return ACAS_SubType::Mult_below_above;
+ if (m9 == 1 && m28 == 0) return ACAS_SubType::One_threat;
+ if (m9 == 1 && m28 == 1) return ACAS_SubType::Mult_same_direction;
+ std::cerr << "BDS30_ACAS_SubType parse_sum(std::string& msg) parse error!\n";
+ return ACAS_SubType::NO_RA;
+ }
+
+
+ void parse(std::string& msg_bin) {
+ get_bin<32 + 22, 1>(msg_bin, Do_not_pass_below);
+ get_bin<32 + 23, 1>(msg_bin, Do_not_pass_above);
+ get_bin<32 + 24, 1>(msg_bin, Do_not_turn_left);
+ get_bin<32 + 25, 1>(msg_bin, Do_not_turn_right);
+ get_bin<32 + 28, 2, Threat_Type_Indicator>(msg_bin, threat_Type_Indicator);
+ get_bin<32 + 30, 26>(msg_bin, threat_data);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(Do_not_pass_below)
+ Ret_J(Do_not_pass_above)
+ Ret_J(Do_not_turn_left)
+ Ret_J(Do_not_turn_right)
+ Ret_J(threat_Type_Indicator)
+ Ret_J(threat_data)
+ return ret;
+ }
+
+ void set(std::string& msg_bin) {
+ set_bin<32, 4>(msg_bin, 3);
+ set_bin<36, 4>(msg_bin, 0);
+ set_bin<32 + 22, 1>(msg_bin, Do_not_pass_below);
+ set_bin<32 + 23, 1>(msg_bin, Do_not_pass_above);
+ set_bin<32 + 24, 1>(msg_bin, Do_not_turn_left);
+ set_bin<32 + 25, 1>(msg_bin, Do_not_turn_right);
+ set_bin<60, 2>(msg_bin, static_cast(threat_Type_Indicator));
+ set_bin<62, 26>(msg_bin, threat_data);
+ }
+};
+T_Parser(ACAS_Active_Resolution_Advisory_9_56)
+
+}
\ No newline at end of file
diff --git a/SSR/ADS_B/ADS_B.cpp b/SSR/ADS_B/ADS_B.cpp
new file mode 100644
index 0000000..a441957
--- /dev/null
+++ b/SSR/ADS_B/ADS_B.cpp
@@ -0,0 +1,4 @@
+#include "ADS_B.h"
+namespace ADS_B {
+
+}
diff --git a/SSR/ADS_B/ADS_B.h b/SSR/ADS_B/ADS_B.h
new file mode 100644
index 0000000..176459a
--- /dev/null
+++ b/SSR/ADS_B/ADS_B.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include
+#include "ADS_B.hpp"
+// DF = 17 18 19
+
+namespace SSR::ADS_B {
+
+ template using Base = ADS_B_T::ADS_B_Base_Builder;
+ template using BDS09 = ADS_B_T::BDS09_Base;
+ template using BDS65 = ADS_B_T::BDS65_Base;
+ template using BDS61 = ADS_B_T::BDS61_Base;
+ // 身份
+ ADD_112_2(Aircraft_identification_BDS08, ADS_B_T::ADS_B_Base_Builder, ADS_B_T::BDS08_Aircraft_identification)
+
+ // 空中位置
+ ADD_112_3(Airborne_Position_BDS05_v01, Base, ADS_B_T::BDS05_Airborne_Position, ADS_B_T::BDS05_v01)
+ ADD_112_3(Airborne_Position_BDS05_v2, Base, ADS_B_T::BDS05_Airborne_Position, ADS_B_T::BDS05_v2)
+
+ // 地表位置
+ ADD_112_2(Surface_Position_BDS06, Base, ADS_B_T::BDS06_Surface_Position)
+
+ // 速度消息
+ ADD_112_4(Ground_Speed_BDS09_v0, Base, BDS09, ADS_B_T::BDS09_Ground_Speed, ADS_B_T::BDS09_v0)
+ ADD_112_4(Ground_Speed_BDS09_v12, Base, BDS09, ADS_B_T::BDS09_Ground_Speed, ADS_B_T::BDS09_v12)
+ ADD_112_4(Airspeed_BDS09_v0, Base, BDS09, ADS_B_T::BDS09_Airspeed, ADS_B_T::BDS09_v0)
+ ADD_112_4(Airspeed_BDS09_v12, Base, BDS09, ADS_B_T::BDS09_Airspeed, ADS_B_T::BDS09_v12)
+
+ // ADS-B 版本消息
+ ADD_112_4(Airborne_Operation_Status_BDS65_ver1, Base, BDS65, ADS_B_T::BDS65_Airborne,
+ ADS_B_T::BDS65_ver1)
+ ADD_112_4(Airborne_Operation_Status_BDS65_ver2, Base, BDS65, ADS_B_T::BDS65_Airborne,
+ ADS_B_T::BDS65_ver2)
+ ADD_112_4(Surface_Operation_Status_BDS65_ver1, Base, BDS65, ADS_B_T::BDS65_Surface,
+ ADS_B_T::BDS65_ver1)
+ ADD_112_4(Surface_Operation_Status_BDS65_ver2, Base, BDS65, ADS_B_T::BDS65_Surface,
+ ADS_B_T::BDS65_ver2)
+
+ // tc=28 飞机状态消息
+ ADD_112_3(Extended_Squitter_Aircraft_Status_Mode_A, Base, BDS61, ADS_B_T::BDS61_Mode_A)
+ ADD_112_3(Extended_Squitter_Aircraft_Status_RA, Base, BDS61, ADS_B_T::BDS61_TCAS_ACAS_RA_Broadcast)
+
+
+}
diff --git a/SSR/ADS_B/ADS_B.hpp b/SSR/ADS_B/ADS_B.hpp
new file mode 100644
index 0000000..cb53f3f
--- /dev/null
+++ b/SSR/ADS_B/ADS_B.hpp
@@ -0,0 +1,891 @@
+#ifndef ADS_B_HPP
+#define ADS_B_HPP
+#include
+#include
+
+#include "../ACAS/ACAS_9_56.hpp"
+#include "../Mode_S/Mode_S.hpp"
+#include "SSR/Msg.h"
+#include "SSR/export_type.h"
+
+
+namespace SSR::ADS_B_T {
+ template
+ struct ADS_B_Base_Builder : with_PI {
+ PROP_T(std::string, icao, "01ABCD")
+ PROP_T(Downlink_Format, df, Downlink_Format::Extended_Squitter_17)
+ PROP_T(int, tc, 0)
+ PROP_T(Transponder_Capability, transponder_capability, Transponder_Capability::Level_2_plus_airborne)
+ virtual Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(icao)
+ Ret_J(df)
+ ret.append(Psc::JSON("tc", std::to_string(tc) + " " + Psc::to_string(type_code_to_enum(tc))));
+ Ret_J(transponder_capability) return ret;
+ }
+ virtual void parse(std::string& msg_bin) {
+ this->df = SSR::decode_df(msg_bin);
+ this->transponder_capability = SSR::decode_transponder_capability(msg_bin);
+ this->icao = SSR::decode_icao(msg_bin);
+ tc = SSR::type_code(msg_bin);
+ }
+ void set(std::string& msg_bin) {
+ check_icao(icao);
+ SSR::set_df(msg_bin, this->df);
+ SSR::set_transponder_capability(msg_bin, this->transponder_capability);
+ SSR::set_icao(msg_bin, this->icao);
+ SSR::set_type_code(msg_bin, this->tc);
+ }
+ };
+ T_Parser(ADS_B_Base_Builder)
+
+ template struct CPR_Air;
+ template struct CPR_Surface;
+
+
+ struct CPR_Data {
+ using time_t = double;
+ struct Info {
+ // 解码cpr判断过期使用的时间
+ // 可以使用报文的时间 或者收到消息的系统的时间(当一批报文一起来,起不到筛选作用)
+ time_t time{};
+ std::shared_ptr msg;
+ void reset() {
+ msg = nullptr;
+ time = 0;
+ }
+
+ Psc::JSON to_json()
+ {
+ auto ret = Psc::JSON::object();
+ ret.append({"time", time});
+ ret.append({"msg", msg ? msg->to_Json() : nullptr});
+ return ret;
+ }
+
+ std::string to_string()
+ {
+ if (msg == nullptr)
+ {
+ return "nullptr";
+ }
+ return std::to_string(time) + " " + msg->to_string();
+ }
+ } even_msg, odd_msg;
+ time_t last_parse_pos_time = 0;
+
+ std::function(const std::string&, const std::string&, time_t, time_t)> global_parse = nullptr;
+ std::function(const std::string&, double lat, double lon, time_t, time_t)> locale_parse = nullptr;
+ std::function encode = nullptr;
+ std::optional pos;
+ std::optional cache_ok_pos;
+ CPR::Frame cpr_format = CPR::Frame::Even;
+ void set_pos(std::optional new_pos, time_t cur_time) {
+ pos = new_pos;
+ if (new_pos != std::nullopt) {
+ cache_ok_pos = new_pos;
+ }
+ last_parse_pos_time = cur_time;
+ }
+ };
+
+
+ template
+ struct CPR_MSG : CPR_Data {
+ virtual ~CPR_MSG() = default;
+ PROP_T_FUN(RET, lon, std::nullopt)
+ PROP_T_FUN(RET, lat, std::nullopt)
+ PROP_T_FUN(CPR::Frame, cpr_format, CPR::Frame::Even);
+ std::string current_state() {
+ std::ostringstream oss;
+ oss << "{" << std::endl;
+ oss << "\tpos:" << (pos.has_value() ? pos->to_string() : "null") << std::endl;
+ oss << "\todd_msg: " + odd_msg.to_string() << std::endl;
+ oss << "\teven_msg: " + even_msg.to_string() << std::endl;
+ oss << "}" << std::endl;
+ return oss.str();
+ }
+
+ Psc::JSON current_state_json() {
+ Psc::JSON ret = Psc::JSON::object();
+ ret.append({"pos", (pos.has_value() ? pos->to_string() : "null")});
+ ret.append({"odd_msg", odd_msg.to_json()});
+ ret.append({"even_msg", even_msg.to_json()});
+ return ret;
+ }
+
+
+ std::string get_cpr_log(std::string type, std::string icao, std::string msg_hex, CPR::Frame f, std::string before_state, std::string after_state) {
+ return
+ "\n===============[" + type + "][" + icao +"]======================\n"
+ "当前收到的消息 msg: " + msg_hex + " frame:" + Psc::to_string(f) + " \n" +
+ "先前的状态:\n" + before_state +
+ "现在的状态:\n" + current_state() +
+ "\n===============[" + type + "][" + icao +"]======================\n"
+ ;
+ }
+
+
+ // 虽然消息已经存在当天的秒数
+ RET parse_message(const std::shared_ptr& msg, double time_s, CPR::D max_speed_m_s, CPR::D max_time_s, const SSR::CPR_CB& cb) {
+ const std::string& msg_bin = msg->msg_bin;
+ std::string msg_hex = bin2hex(msg_bin);
+ std::string icao = msg_hex.substr(2, 6);
+ Info *that, *other;
+ auto f = get_cpr_format();
+ auto before_state = current_state();
+ if (f == CPR::Frame::Even) {
+ //std::cout << "even\n";
+ that = &even_msg;
+ other = &odd_msg;
+ } else {
+ //std::cout << "odd\n";
+ that = &odd_msg;
+ other = &even_msg;
+ }
+ that->msg = msg;
+ that->time = time_s;
+ Log_Type log_type({}, {{"ICAO", icao}, {"Frame_type", Psc::to_string(f)}});
+ std::optional& old_pos = pos;
+ if (old_pos.has_value()) {
+ if (std::abs(that->time - last_parse_pos_time) < max_time_s) {
+ auto new_pos = locale_parse(that->msg->msg_bin, old_pos->lat, old_pos->lon, that->time, last_parse_pos_time);
+ if (new_pos.has_value()) {
+ auto distance_m = CPR::haversine(old_pos.value(), new_pos.value());
+ auto used_time_s = time_s - last_parse_pos_time;
+ auto max_distance = used_time_s * max_speed_m_s;
+ if (distance_m < max_distance) {
+ set_pos(new_pos, time_s);
+ cb(SSR::CPR_Error_Type::Normal, get_cpr_log("本地位置解码", icao, msg_hex, f, before_state, current_state()), msg);
+ // 解码成功返回
+ if (!new_pos.has_value()) return std::nullopt;
+ set_pos(new_pos, time_s);
+ return Pos_Ret(new_pos.value(), that->msg, old_pos.value());
+ } else
+ {
+ // 尝试全局解码
+ cb(SSR::CPR_Error_Type::Local_Speed_Error, get_cpr_log("本地位置解码速度异常舍弃, 尝试全局解码", icao, msg_hex, f, before_state, current_state())
+ + " " + VAR_STR_4(distance_m, max_distance, used_time_s, max_speed_m_s), msg);
+ }
+ } else {
+ cb(SSR::CPR_Error_Type::Unknow_Error, get_cpr_log("未知错误", icao, msg_hex, f, before_state, current_state()), msg);
+ }
+ } else {
+ cb(SSR::CPR_Error_Type::Local_Time_Space_Too_Long, get_cpr_log("本地位置解码时间异常, 尝试全局解码", icao, msg_hex, f, before_state, current_state()), msg);
+ }
+ }
+ // 本地解码失败走到这里 尝试全局解码
+ if(other->msg){
+ if (std::abs(that->time - other->time) < max_time_s) {
+ RET new_pos = global_parse(that->msg->msg_bin, other->msg->msg_bin, that->time, other->time);
+ if (new_pos.has_value()) {
+ if (old_pos.has_value()) {
+ auto distance = CPR::haversine(old_pos.value(), new_pos.value());
+ auto used_time_s = time_s - other->time;
+ auto max_distance = used_time_s * max_speed_m_s;
+ if (distance < max_distance)
+ {
+ cb(SSR::CPR_Error_Type::Normal, get_cpr_log("全局位置解码", icao, msg_hex, f, before_state, current_state()), msg);
+ last_parse_pos_time = time_s;
+ set_pos(new_pos, time_s);
+ return Pos_Ret(new_pos.value(), that->msg, other->msg);
+ } else
+ {
+ // 视为失败
+ cb(SSR::CPR_Error_Type::Global_Speed_Error, get_cpr_log("全局位置解码速度异常,直接舍弃", icao, msg_hex, f, before_state, current_state())
+ + " " + VAR_STR_4(distance, max_distance, used_time_s, max_speed_m_s), msg);
+ }
+ } else {
+ // 第一次全局解码的位置,直接视为成功
+ set_pos(new_pos, time_s);
+ return Pos_Ret(new_pos.value(), that->msg, other->msg);
+ }
+ } else {
+ cb(SSR::CPR_Error_Type::Unknow_Error, get_cpr_log("未知错误", icao, msg_hex, f, before_state, current_state())
+ + " "
+ , msg);
+ }
+
+ } else {
+ cb(SSR::CPR_Error_Type::Global_Time_Space_Too_Long, get_cpr_log("本地位置解码时间异常, 尝试全局解码", icao, msg_hex, f, before_state, current_state()), msg);
+ }
+ } else {
+ // 消息不足 放弃解码
+ cb(SSR::CPR_Error_Type::Msg_Lack, get_cpr_log(" 消息不足 放弃解码", icao, msg_hex, f, before_state, current_state()), msg);
+ }
+ // 两种解码尝试都失败 尝试这里
+ last_parse_pos_time = 0;
+ pos = std::nullopt;
+ other->reset();
+ return std::nullopt;
+ }
+
+ virtual void parse(std::string& msg_bin) {
+ get_bin<53, 1, CPR::Frame>(msg_bin, cpr_format);
+ }
+ virtual Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(pos)
+ Ret_J(cpr_format)
+ return ret;
+ }
+ virtual void set(std::string& msg_bin) {
+ set_bin<53, 1>(msg_bin, static_cast(this->cpr_format));
+ if (pos.has_value())
+ {
+ set_bin<54, 34>(msg_bin, encode(this->pos->lat, this->pos->lon, this->cpr_format));
+ }
+ }
+ private:
+ std::string sub_type_name() {
+ if (std::is_base_of, That>::value) {
+ return "airbore_postation";
+ } else if (std::is_base_of, That>::value) {
+ return "surface_postation";
+ } else {
+ return "unknown_CPR";
+ }
+ }
+ };
+
+ template
+ struct CPR_Air : CPR_MSG {
+ CPR_Air() {
+ this->global_parse = CPR::airborne_position;
+ this->locale_parse = CPR::airborne_position_with_ref;
+ this->encode = CPR::lat_lon_airborne_34;
+ }
+ ~CPR_Air() override = default;
+ };
+
+ template
+ struct CPR_Surface : CPR_MSG {
+ CPR_Surface() {
+ this->global_parse = [this](const std::string& msg0, const std::string& msg1, time_t t0, time_t t1)->std::optional{
+ if(!base_station_pos.has_value()){
+ return std::nullopt;
+ }
+ return CPR::surface_position(msg0, msg1, t0, t1, base_station_pos.value());
+ };
+ this->locale_parse = CPR::surface_position_with_ref;
+ this->encode = CPR::lat_lon_surface_34;
+ }
+ std::optional base_station_pos;
+ };
+
+
+ template
+ struct BDS05_v01 {
+ PROP_Bit_T(1, single_antenna_flag, 0)
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(single_antenna_flag)
+ return ret;
+ }
+ void parse(std::string& msg_bin) { single_antenna_flag = get_bin<39, 1>(msg_bin); }
+ void set(std::string& msg_bin) { set_bin<39, 1>(msg_bin, single_antenna_flag); }
+ };
+ T_Parser(BDS05_v01)
+ template
+ struct BDS05_v2 {
+ PROP_Bit_T(1, NICb, 0)
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(NICb)
+ return ret;
+ }
+ void parse(std::string& msg_bin) { NICb = get_bin<39, 1>(msg_bin); }
+ void set(std::string& msg_bin) { set_bin<39, 1>(msg_bin, NICb); }
+ };
+ T_Parser(BDS05_v2)
+
+ // TC=9–18:空中位置,气压高度编码(以英尺为单位)
+ // TC=20–22:机载位置,GNSS 高度编码(以米为单位)
+ template
+ struct BDS05_Airborne_Position : BDS05, CPR_Air {
+ PROP_T(Altitude_type, altitude_type, Altitude_type::Baro);
+ PROP_T(double, alt_meter, 0);
+ PROP_Bit_T(1, time, 0)
+ PROP_T(Surveillance_Status, surveillance_status, Surveillance_Status::NoCondition)
+ void set(std::string& msg_bin) override {
+ CPR_Air::set(msg_bin);
+ set_type_code(msg_bin, altitude_type == Altitude_type::Baro ? 9 : 20);
+ set_bin<37, 2>(msg_bin, static_cast(surveillance_status));
+ set_bin<40, 12>(msg_bin, encode_altitude_code_12(alt_meter, altitude_type));
+ set_bin<52, 1>(msg_bin, time);
+ }
+ void parse(std::string& msg_bin) override {
+ CPR_Air::parse(msg_bin);
+ auto tc = get_type_code(msg_bin);
+ if (tc >= 9 && tc <= 18) {
+ altitude_type = Altitude_type::Baro;
+ }
+ if (tc >= 20 && tc <= 22) {
+ altitude_type = Altitude_type::GNSS;
+ }
+ get_bin<37, 2, Surveillance_Status>(msg_bin, surveillance_status);
+ // 40 在版本1 2的区别中
+ alt_meter = decode_altitude_12_meter(msg_bin.substr(40, 12), altitude_type);
+ get_bin<52, 1>(msg_bin, time);
+ }
+ Psc::JSON toJson() override {
+ Psc::JSON ret = Psc::JSON::object();
+ ret.append_list(CPR_Air::toJson().children);
+ Ret_J(surveillance_status)
+ Ret_J(alt_meter)
+ Ret_J(time)
+ return ret;
+ }
+ };
+ T_Parser(BDS05_Airborne_Position)
+ template
+ struct BDS06_Surface_Position : BDS06, CPR_Surface {
+ PROP_T(Altitude_type, altitude_type, Altitude_type::Baro)
+ PROP_T(double, altitude, 0)
+ PROP_T(double, movement, 0)
+ PROP_Bit_T(1, time, 0)
+ PROP_Range_T(double, 0.0, 360.0, track_degree, 0)
+ void parse(std::string& msg_bin) override {
+ CPR_Surface::parse(msg_bin);
+ auto tc = get_type_code(msg_bin);
+ if (tc >= 9 && tc <= 18) {
+ altitude_type = Altitude_type::Baro;
+ }
+ if (tc >= 20 && tc <= 22) {
+ altitude_type = Altitude_type::GNSS;
+ }
+ movement = decode_movement_7(msg_bin.substr(37, 7));
+ track_degree = decode_ground_track_7(msg_bin.substr(44, 8));
+ get_bin<52, 1>(msg_bin, time);
+ }
+ Psc::JSON toJson() override {
+ Psc::JSON ret = Psc::JSON::object();
+ ret.append_list(CPR_Surface::toJson().children);
+ Ret_J(altitude_type)
+ Ret_J(altitude)
+ Ret_J(movement)
+ Ret_J(time)
+ return ret;
+ }
+ void set(std::string& msg_bin) override {
+ CPR_Surface::set(msg_bin);
+ set_type_code(msg_bin, altitude_type == Altitude_type::Baro ? 9 : 20);
+ set_bin<37, 7>(msg_bin, encode_movement_7(movement));
+ set_bin<44, 1>(msg_bin, 1);
+ set_bin<45, 7>(msg_bin, encode_ground_track_7(track_degree));
+ set_bin<52, 1>(msg_bin, time);
+ }
+ };
+ T_Parser(BDS06_Surface_Position)
+ template
+ struct BDS08_Aircraft_identification : BDS08 {
+ // 八位 #ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ###############0123456789######
+ // 不同时间飞行同一航线的不同飞机将共享相同的呼号。
+ PROP_T(std::string, call_sign, "???")
+ PROP_T(Vortex_Type, vortex_type, Vortex_Type::Glider)
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(call_sign)
+ Ret_J(vortex_type)
+ return ret;
+ }
+ void parse(std::string& msg_bin) {
+ call_sign = SSR::get_call_sign(msg_bin);
+ vortex_type = SSR::parse_vortex_type(msg_bin);
+ }
+ void set(std::string& msg_bin) {
+ if (call_sign.size() != 8 || !std::all_of(call_sign.begin(), call_sign.end(), [](char c) {
+ //std::isxdigit(c)
+ return std::isupper(c) || std::isdigit(c);
+ }))
+ {
+ CE(true, "不合法的call_sign:" + call_sign)
+ }
+ SSR::set_call_sign(msg_bin, call_sign);
+ auto tc_ca = map1[vortex_type];
+ set_type_code(msg_bin, tc_ca.first);
+ set_category(msg_bin, tc_ca.second);
+ }
+ };
+ T_Parser(BDS08_Aircraft_identification)
+
+ // BDS09 tc=19 速度报文
+ template
+ struct BDS09_v0 {
+ PROP_Bit_T(3, NUCv, 0)
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(NUCv)
+ return ret;
+ }
+ void parse(std::string& msg_bin) { NUCv = get_bin<42, 3>(msg_bin); }
+ void set(std::string& msg_bin) { set_bin<42, 3>(msg_bin, NUCv); }
+ };
+ T_Parser(BDS09_v0)
+ template
+ struct BDS09_v12 {
+ PROP_Bit_T(3, NACv, 0)
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(NACv)
+ return ret;
+ }
+ void parse(std::string& msg_bin) { NACv = get_bin<42, 3>(msg_bin); }
+ void set(std::string& msg_bin) { set_bin<42, 3>(msg_bin, NACv); }
+ };
+ T_Parser(BDS09_v12)
+ template
+ struct BDS09_Base : BDS09 {
+ PROP_T(Source, vertical_rate_source, Source::GNSS)
+ PROP_T(RET, vertical_rate, std::nullopt)
+ PROP_Bit_T(1, intent_change_flag, 0)
+ PROP_Bit_T(1, IFR_capability_flag, 0)
+ PROP_T(RET, GNSS_barometric_altitudes_difference, std::nullopt);
+ void set(std::string& msg_bin) {
+ set_bin<32, 5>(msg_bin, 19);
+ set_bin<40, 1>(msg_bin, intent_change_flag);
+ set_bin<41, 1>(msg_bin, IFR_capability_flag);
+ set_bin<67, 1>(msg_bin, static_cast(vertical_rate_source));
+ if (vertical_rate.has_value()) set_bin<68, 10>(msg_bin, vertical_rate_code_10(vertical_rate.value()));
+ if (GNSS_barometric_altitudes_difference.has_value())
+ set_bin<80, 8>(
+ msg_bin, GNSS_barometric_altitudes_difference_8(GNSS_barometric_altitudes_difference.value()));
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(intent_change_flag)
+ Ret_J(IFR_capability_flag)
+ Ret_J(vertical_rate_source)
+ Ret_J(vertical_rate)
+ Ret_J(GNSS_barometric_altitudes_difference)
+ return ret;
+ }
+ void parse(std::string& msg_bin) {
+ intent_change_flag = get_bin<40, 1>(msg_bin);
+ IFR_capability_flag = get_bin<41, 1>(msg_bin);
+ vertical_rate_source = get_bin<67, 1, Source>(msg_bin);
+ int vertical_rate_v = get_bin<69, 9>(msg_bin);
+ if (vertical_rate_v != 0)
+ {
+ int sign = get_bin<68, 1>(msg_bin) ? -1 : 1;
+ vertical_rate = sign * (vertical_rate_v - 1) * 64;
+ }
+ int diff_v = get_bin<81, 7>(msg_bin);
+ if (diff_v != 0)
+ {
+ int sign = get_bin<80, 1>(msg_bin) ? -1 : 1;
+ GNSS_barometric_altitudes_difference = sign * diff_v;
+ }
+ }
+ };
+ T_Parser(BDS09_Base)
+
+
+ template
+ struct BDS09_Ground_Speed {
+ PROP_T(Ground_Speed_Type, sub_type, Ground_Speed_Type::Ground_Normal);
+ PROP_Range_T(double, 0.0, 360.0, magnetic_heading, 0.0);
+ PROP_T(double, speed, 0);
+ void set(std::string& msg_bin) {
+ set_bin<37, 3>(msg_bin, static_cast(sub_type));
+ set_bin<45, 22>(msg_bin, encode_velocity_22(sub_type, magnetic_heading, speed));
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(sub_type)
+ Ret_J(magnetic_heading)
+ Ret_J(speed)
+ return ret;
+ }
+ void parse(std::string& msg_bin) {
+ sub_type = get_bin<37, 3, Ground_Speed_Type>(msg_bin);
+ Ground_Speed ground_speed = surface_velocity(msg_bin, sub_type);
+ magnetic_heading = ground_speed.angle;
+ speed = ground_speed.speed;
+ }
+ };
+ T_Parser(BDS09_Ground_Speed)
+ template
+ struct BDS09_Airspeed {
+ PROP_Range_T(RET, 0.0, 360.0, magnetic_heading, std::nullopt);
+ PROP_T(Air_Speed_Code_Type, sub_type, Air_Speed_Code_Type::Air_Normal);
+ PROP_T(Airspeed_type, airspeed_type, Airspeed_type::Indicated_airspeed_IAS);
+ PROP_T(RET, speed, std::nullopt);
+ void set(std::string& msg_bin) {
+ set_bin<37, 3>(msg_bin, static_cast(sub_type));
+ if (magnetic_heading.has_value()) {
+ int encoded_heading = static_cast(std::round(magnetic_heading.value() * 1024 / 360));
+ std::bitset<10> HDG_bits(encoded_heading);
+ set_bin<45, 11>(msg_bin, "1" + HDG_bits.to_string());
+ }
+ set_bin<56, 1>(msg_bin, static_cast(airspeed_type));
+ if (speed.has_value()) {
+ double airspeed = speed.value();
+ int encoded_airspeed = 0;
+ if (sub_type == Air_Speed_Code_Type::Air_Normal) {
+ // Sub-type 1: Speed = Decimal value - 1
+ encoded_airspeed = static_cast(std::round(airspeed)) + 1;
+ } else if (sub_type == Air_Speed_Code_Type::Air_Supersonic) {
+ // Sub-type 2: Speed = 4 x (Decimal value - 1)
+ encoded_airspeed = static_cast(std::round(airspeed / 4)) + 1;
+ }
+ set_bin<57, 10>(msg_bin, std::bitset<10>(encoded_airspeed).to_string());
+ }
+ }
+ void parse(std::string& msg_bin) {
+ sub_type = get_bin<37, 3, Air_Speed_Code_Type>(msg_bin);
+ if (get_bin<45, 1>(msg_bin) == 1) {
+ int magnetic_heading_code = get_bin<46, 10>(msg_bin);
+ magnetic_heading = magnetic_heading_code * 360.0 / 1024.0;
+ }
+ airspeed_type = static_cast(get_bin<56, 1>(msg_bin));
+ if (sub_type == Air_Speed_Code_Type::Air_Normal) {
+ speed = get_bin<57, 10>(msg_bin) - 1;
+ }
+ if (sub_type == Air_Speed_Code_Type::Air_Supersonic) {
+ speed = 4 * (get_bin<57, 10>(msg_bin) - 1);
+ }
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(sub_type)
+ Ret_J(magnetic_heading)
+ Ret_J(speed)
+ return ret;
+ }
+ };
+ T_Parser(BDS09_Airspeed)
+ // 操作状态
+ template
+ struct BDS65_ver1 {
+ PROP_Bit_T(1, NICs, 0)
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(NICs)
+ return ret;
+ }
+ void parse(std::string& msg_bin) { NICs = get_bin<76, 1>(msg_bin); }
+ void set(std::string& msg_bin) { set_bin<76, 1>(msg_bin, NICs); }
+ };
+ T_Parser(BDS65_ver1)
+ template
+ struct BDS65_ver2 {
+ PROP_Bit_T(1, NICa, 0)
+ PROP_Bit_T(1, NICc, 0)
+ PROP_Bit_T(1, SILs, 0)
+ void set(std::string& msg_bin) {
+ set_bin<76, 1>(msg_bin, NICa);
+ set_bin<51, 1>(msg_bin, NICc);
+ set_bin<87, 1>(msg_bin, SILs);
+ }
+ void parse(std::string& msg_bin) {
+ NICa = get_bin<76, 1>(msg_bin);
+ NICc = get_bin<51, 1>(msg_bin);
+ SILs = get_bin<87, 1>(msg_bin);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(NICa)
+ Ret_J(NICc)
+ Ret_J(SILs)
+ return ret;
+ }
+ };
+ T_Parser(BDS65_ver2)
+ template
+ struct BDS65_Base : BDS65 {
+ PROP_Bit_T(4, NACp_4, 0)
+ PROP_Bit_T(2, SIL, 0)
+ PROP_Bit_T(1, Horizontal_Reference_direction_1, 0)
+ PROP_Range_T(int, 1, 2, ADS_B_version, 0)
+ void set(std::string& msg_bin) {
+ set_bin<32, 5>(msg_bin, 31);
+ set_bin<76, 4>(msg_bin, NACp_4);
+ set_bin<82, 2>(msg_bin, SIL);
+ set_bin<85, 1>(msg_bin, Horizontal_Reference_direction_1);
+ set_bin<72, 3>(msg_bin, ADS_B_version);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<76, 4>(msg_bin, NACp_4);
+ get_bin<82, 2>(msg_bin, SIL);
+ get_bin<85, 1>(msg_bin, Horizontal_Reference_direction_1);
+ get_bin<72, 3>(msg_bin, ADS_B_version);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(NACp_4)
+ Ret_J(SIL)
+ Ret_J(Horizontal_Reference_direction_1)
+ Ret_J(ADS_B_version)
+ return ret;
+ }
+ };
+ T_Parser(BDS65_Base)
+ template
+ struct BDS65_Airborne {
+ PROP_Bit_T(16, Airborne_Operational_mode_codes, 0)
+ PROP_Bit_T(2, Geometric_vertical_accuracy, 0)
+ PROP_Bit_T(2, Barometric_Altitude_Integrity, 0)
+ void set(std::string& msg_bin) {
+ set_bin<37, 3>(msg_bin, 0);
+ set_bin<40, 16>(msg_bin, Airborne_Operational_mode_codes);
+ set_bin<80, 2>(msg_bin, Geometric_vertical_accuracy);
+ set_bin<84, 1>(msg_bin, Barometric_Altitude_Integrity);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<40, 16>(msg_bin, Airborne_Operational_mode_codes);
+ get_bin<80, 2>(msg_bin, Geometric_vertical_accuracy);
+ get_bin<84, 1>(msg_bin, Barometric_Altitude_Integrity);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(Airborne_Operational_mode_codes)
+ Ret_J(Geometric_vertical_accuracy)
+ Ret_J(Barometric_Altitude_Integrity)
+ return ret;
+ }
+ };
+ T_Parser(BDS65_Airborne)
+ template
+ struct BDS65_Surface {
+ PROP_Bit_T(16, Surface_Operational_mode_codes, 0)
+ PROP_Bit_T(2, Track_angle_or_heading, 0)
+ void set(std::string& msg_bin) {
+ set_bin<37, 3>(msg_bin, 1);
+ set_bin<40, 16>(msg_bin, Surface_Operational_mode_codes);
+ set_bin<84, 1>(msg_bin, Track_angle_or_heading);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<40, 16>(msg_bin, Surface_Operational_mode_codes);
+ get_bin<84, 1>(msg_bin, Track_angle_or_heading);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(Surface_Operational_mode_codes)
+ Ret_J(Track_angle_or_heading)
+ return ret;
+ }
+ };
+ T_Parser(BDS65_Surface)
+
+// 61 1 6
+// Extended Squitter Aircraft Status 1 .0 s
+// 62 1 6
+// Target State and Status Information 0.5 s
+ // tc = 28 Extended squitter aircraft emergency priority status
+ // Extended_Squitter_Aircraft_Status
+
+
+ template
+ struct BDS61_Base : BDS61 {
+ PROP_T(Emergency_Type, emergency_state, Emergency_Type::No_Emergency)
+ PROP_Bit_T(2, sub_type, 0)
+ void set(std::string& msg_bin) {
+ set_bin<32, 5>(msg_bin, 28);
+ set_bin<32 + 5, 3>(msg_bin, 1);
+ set_bin<32 + 8, 3>(msg_bin, static_cast(emergency_state));
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<32 + 8, 4>(msg_bin, emergency_state);
+ get_bin<32 + 5, 3>(msg_bin, sub_type);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(emergency_state)
+ Ret_J(sub_type)
+ return ret;
+ }
+ };
+ T_Parser(BDS61_Base)
+
+ template
+ struct BDS61_Mode_A {
+ //PROP_Bit_32T(13, mode_a, 0)
+ PROP_T(std::string, mode_a, "??")
+ void set(std::string& msg_bin) {
+ set_bin<32 + 5, 3>(msg_bin, 1);
+ set_bin<32 + 11, 13>(msg_bin, encode_squawk13(mode_a));
+ }
+ void parse(std::string& msg_bin) {
+ //get_bin<32 + 11, 13>(msgmsg_bin, mode_a);
+ mode_a = decode_squawk13(std::bitset<13>(get_bin<32 + 11, 13>(msg_bin)).to_string());
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(mode_a)
+ return ret;
+ }
+ };
+ T_Parser(BDS61_Mode_A)
+
+ template
+ struct BDS61_TCAS_ACAS_RA_Broadcast : ACAS_Active_Resolution_Advisory_9_56 {};
+ T_Parser(BDS61_TCAS_ACAS_RA_Broadcast)
+
+
+
+ enum Alt_Source {
+ MCP_FCU,
+ FMS
+ };
+ // Target_State_and_Status_Information
+
+ template
+ struct BDS62_Base : BDS62 {
+ PROP_Bit_T(2, sub_type, 0)
+ void set(std::string& msg_bin) {
+ set_bin<32, 5>(msg_bin, 29);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<32 + 5, 2>(msg_bin, sub_type);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(sub_type)
+ return ret;
+ }
+ };
+ T_Parser(BDS62_Base)
+
+ template
+ struct BDS62_ver1 {
+ PROP_Bit_T(2, Vertical_Data_Available_Source_Indicator, 0) // §B.2.3.9.3
+ PROP_Bit_T(1, Target_Altitude_Type, 0) //§B.2.3.9.4
+ PROP_Bit_T(1, Backward_Compatibility_Flag, 0)
+ PROP_Bit_T(2, Target_Altitude_Capability, 0) // §B.2.3.9.5
+ PROP_Bit_T(2, Vertical_Mode_Indicator, 0) // §B.2.3.9.6
+ PROP_Bit_T(10, Target_Altitude, 0) // §B.2.3.9.7
+ PROP_Bit_T(2, Horizontal_Data_Source_Indicator, 0) // §B.2.3.9.8
+ PROP_Bit_T(2, Track_Angle, 0) // §B.2.3.9.9
+ PROP_Bit_T(1, Track_Indicator, 0) // §B.2.3.9.10
+ PROP_Bit_T(2, Horizontal_Mode_Indicator, 0) // §B.2.3.9.11
+ PROP_Bit_T(4, NACp, 0) // §B.2.3.9.12
+ PROP_Bit_T(4, NIC_BARO, 0) // §B.2.3.9.13
+ PROP_Bit_T(2, SIL, 0) // §B.2.3.9.14
+ PROP_Bit_T(2, Capability_Mode_Codes, 0) // §B.2.3.9.15
+ PROP_Bit_T(2, Emergency_Priority_Status, 0) // §B.2.3.9.16
+
+ void set(std::string& msg_bin) {
+ set_bin<32 + 5, 2>(msg_bin, 0);
+ }
+ void parse(std::string& msg_bin) {
+
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ return ret;
+ }
+ };
+ T_Parser(BDS62_ver1)
+
+ template
+ struct BDS62_ver2 {
+ PROP_Bit_T(1, SIL_SUPPLEMENT, 0) // (0 = Per Hour, 1 = Per Sample)
+ PROP_Bit_T(1, selected_altitude_type, 0) // (0 = MCP/FCU, 1 = FMS)
+ PROP_T(std::optional, selected_altitude, 0)
+ PROP_Range_T(std::optional, 0, 408.0, barometric_pressure, 0);
+ PROP_Range_T(std::optional, -180.0, 180.0, select_heading, 0);
+ PROP_Bit_T(4, NACp, 0)
+ PROP_Bit_T(1, NIC_BARO, 0)
+ PROP_Bit_T(2, SIL, 0)
+ PROP_Bit_T(2, MCP_FCU_State, 0)
+ PROP_Bit_T(1, auto_pilot_engaged, 0)
+ PROP_Bit_T(1, VANV_mode_engaged, 0)
+ PROP_Bit_T(1, altitude_hold_mode_engaged, 0)
+ PROP_Bit_T(1, Reserved_ADS_R_Flag, 0)
+ PROP_Bit_T(1, approach_mode_engaged, 0)
+ PROP_Bit_T(1, TCAS_ACAS_operational, 0)
+ PROP_Bit_T(1, LNAV_mode_engaged, 0)
+ void set(std::string& msg_bin) {
+ set_bin<32 + 5, 2>(msg_bin, 1);
+ set_bin<32 + 7, 1>(msg_bin, SIL_SUPPLEMENT);
+ set_bin<32 + 8, 1>(msg_bin, selected_altitude_type);
+ if (selected_altitude.has_value()) {
+ if (selected_altitude_type == 0) { //MCP/FCU
+ set_bin<32 + 9, 11>(msg_bin, selected_altitude.value()/32 + 1);
+ } else { // FMS
+ set_bin<32 + 9, 11>(msg_bin, selected_altitude.value());
+ }
+ }
+ if (barometric_pressure.has_value()) {
+ set_bin<32 + 20, 9>(msg_bin, barometric_pressure.value()/0.8 + 1);
+ }
+ if (select_heading.has_value()) {
+ set_bin<32 + 29, 1>(msg_bin, 1);
+ int sign = select_heading.value() > 0 ? 0 : 1;
+ set_bin<32 + 30, 1>(msg_bin, sign);
+ int select_heading_code = std::abs(select_heading.value() * 256.0/180.0);
+ set_bin<32 + 31, 8>(msg_bin, select_heading_code);
+ } else {
+ set_bin<32 + 29, 1>(msg_bin, 0);
+ }
+ set_bin<32 + 39, 4>(msg_bin, NACp);
+ set_bin<32 + 43, 1>(msg_bin, NIC_BARO);
+ set_bin<32 + 44, 2>(msg_bin, SIL);
+ set_bin<32 + 46, 1>(msg_bin, MCP_FCU_State);
+ set_bin<32 + 47, 1>(msg_bin, auto_pilot_engaged);
+ set_bin<32 + 48, 1>(msg_bin, VANV_mode_engaged);
+ set_bin<32 + 49, 1>(msg_bin, altitude_hold_mode_engaged);
+ set_bin<32 + 50, 1>(msg_bin, Reserved_ADS_R_Flag);
+ set_bin<32 + 51, 1>(msg_bin, approach_mode_engaged);
+ set_bin<32 + 52, 1>(msg_bin, TCAS_ACAS_operational);
+ set_bin<32 + 53, 1>(msg_bin, LNAV_mode_engaged);
+ }
+ void parse(std::string& msg_bin) {
+ get_bin<32 + 7, 1>(msg_bin, SIL_SUPPLEMENT);
+ get_bin<32 + 8, 1>(msg_bin, selected_altitude_type);
+ int selected_altitude_code = get_bin<32 + 9, 11>(msg_bin);
+ if (selected_altitude_code != 0) {
+ if (selected_altitude_type == 0) { //MCP/FCU
+ selected_altitude = (selected_altitude_code - 1) * 32;
+ } else { // FMS
+ selected_altitude = selected_altitude_code;
+ }
+ }
+ auto barometric_pressure_code = get_bin<32 + 20, 9>(msg_bin);
+ if (barometric_pressure_code != 0) {
+ barometric_pressure = (get_bin<32 + 20, 9>(msg_bin) - 1) * 0.8;
+ }
+ bool enable = get_bin<32 + 29, 1>(msg_bin);
+ if (enable) {
+ double sign = get_bin<32 + 30, 1>(msg_bin) == 0 ? 1.0 : -1.0;
+ int select_heading_code = get_bin<32 + 31, 8>(msg_bin);
+ select_heading = sign * select_heading_code * 180.0/256.0;
+ }
+ get_bin<32 + 39, 4>(msg_bin, NACp);
+ get_bin<32 + 43, 1>(msg_bin, NIC_BARO);
+ get_bin<32 + 44, 2>(msg_bin, SIL);
+ get_bin<32 + 46, 1>(msg_bin, MCP_FCU_State);
+ get_bin<32 + 47, 1>(msg_bin, auto_pilot_engaged);
+ get_bin<32 + 48, 1>(msg_bin, VANV_mode_engaged);
+ get_bin<32 + 49, 1>(msg_bin, altitude_hold_mode_engaged);
+ get_bin<32 + 50, 1>(msg_bin, Reserved_ADS_R_Flag);
+ get_bin<32 + 51, 1>(msg_bin, approach_mode_engaged);
+ get_bin<32 + 52, 1>(msg_bin, TCAS_ACAS_operational);
+ get_bin<32 + 53, 1>(msg_bin, LNAV_mode_engaged);
+ }
+ Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(SIL_SUPPLEMENT)
+ Ret_J(selected_altitude_type)
+ Ret_J(selected_altitude)
+ Ret_J(barometric_pressure)
+ Ret_J(select_heading)
+ Ret_J(NACp)
+ Ret_J(NIC_BARO)
+ Ret_J(SIL)
+ Ret_J(MCP_FCU_State)
+ Ret_J(auto_pilot_engaged)
+ Ret_J(VANV_mode_engaged)
+ Ret_J(altitude_hold_mode_engaged)
+ Ret_J(Reserved_ADS_R_Flag)
+ Ret_J(approach_mode_engaged)
+ Ret_J(TCAS_ACAS_operational)
+ Ret_J(LNAV_mode_engaged)
+ return ret;
+ }
+ };
+ T_Parser(BDS62_ver2)
+
+}
+#endif
diff --git a/SSR/Aircraft_Info.cpp b/SSR/Aircraft_Info.cpp
new file mode 100644
index 0000000..ad1d32d
--- /dev/null
+++ b/SSR/Aircraft_Info.cpp
@@ -0,0 +1,561 @@
+#include "Aircraft_Info.h"
+#include "Core/Statistics/Frequency_Limit.h"
+#include "convert/SBS.h"
+#include "export.h"
+using namespace Psc;
+#define Parse_no_json(t, Field) std::lock_guard g(info.Field.mtx.mtx); \
+init_that(info, #Field, info.Field, mode_s_msg); \
+auto& t = info.Field.value.value();
+
+
+#define Parse(t, Field) std::lock_guard mtx_##Field(info.Field.mtx.mtx); \
+init_that(info, #Field, info.Field, mode_s_msg); \
+auto& t = info.Field.value.value(); \
+msg_json.append_list(t.toJson().children);
+
+
+
+#define checkLength(len) \
+if (msg_hex.size() != len) { \
+ parse_call_back(Parse_Call_Back_Type::Length_Error, nullptr, to_string(df), {}, nullptr, mode_s_msg); \
+ return false; \
+}
+
+
+
+namespace SSR {
+ Parse_Call_Back parse_call_back = [](
+ SSR::Parse_Call_Back_Type type, Aircraft_Info* info,
+ const std::string& field_name, std::vector bds_list, void*, SSR::P_S mode_s_msg) {
+ if (type == Parse_Call_Back_Type::Normal_Block) return;
+ auto& msg_hex = mode_s_msg->msg_hex;
+ auto& msg = mode_s_msg->msg_bin;
+ auto& df = mode_s_msg->df;
+ auto& icao = mode_s_msg->icao;
+ std::string bds_list_str;
+ for (size_t i = 0; i < bds_list.size(); i++) {
+ bds_list_str += bds_list[i] + "_";
+ }
+ if (!bds_list_str.empty()) {
+ bds_list_str.pop_back();
+ }
+ Log_Type lt({}, {
+ {"Parse_Call_Back_Type", to_string(type)},
+ {"bds_list_str", bds_list_str},
+ {"ICAO", icao},
+ {"DF", to_string(df)},
+ {"signal_level", std::to_string((int)mode_s_msg->signal_level)},
+ {"mlat", mode_s_msg->mlat_timestamp.to_string()},
+ {"msg", msg_hex}
+ });
+ if (type == Parse_Call_Back_Type::Length_Error) {
+ mode_s_logger->error(to_string(df) + " length error", {},
+ "should:" + std::to_string(mode_s_msg->msg_hex.size()) + " msg_hex_size:" + std::to_string(msg_hex.size()) + " icao:"
+ + icao + "; msg_hex:" + msg_hex);
+ }
+ mode_s_logger->error("", lt, "");
+ };
+ Parse_Pos_Call_Back parse_pos_call_back = [](Aircraft_Info* info, P_S mode_s_msg, bool surface) {
+ if (surface) {
+ mode_s_logger->debug("surface/地面轨迹", {}, info->surface_pos_track_list.to_string());
+ } else {
+ mode_s_logger->debug("air/轨迹", {}, info->air_pos_track_list.to_string());
+ }
+ };
+
+ Parse_OK_Json_Call_Back parse_ok_json = [](Aircraft_Info* aircraft_info, P_S mode_s_msg, Psc::JSON msg_json) {
+ auto& icao = mode_s_msg->icao;
+ auto& msg_hex = mode_s_msg->msg_hex;
+ auto& df = mode_s_msg->df;
+ Log_Type lt({}, {
+ {"ICAO", icao},
+ {"DF", std::to_string(static_cast(df))},
+ {"signal_level", std::to_string((int)mode_s_msg->signal_level)},
+ {"mlat", mode_s_msg->mlat_timestamp.to_string()},
+ {"msg", msg_hex}
+ });
+ mode_s_logger->debug("mode_s/json", lt, msg_json.to_json_string());
+ };
+ void set_logger(BaseLogger* logger) {
+ delete mode_s_logger;
+ mode_s_logger = logger;
+ }
+
+
+ bool check_new_prase_pos(ADS_B_T::CPR_Data & t, std::optional& tp, const std::optional& last, SSR::P_S mode_s_msg) {
+ if (tp == std::nullopt) return false;
+ if (last == std::nullopt) return true;
+ return true;
+ }
+ constexpr double s_ns = 1000000000.0;
+
+
+
+ // cpr回调
+ CPR_CB cpr_cb = [](CPR_Error_Type t, const std::string& log, P_S msg) {
+ if (mode_s_logger) mode_s_logger->debug("CPR/"+ to_string(t), {}, log);
+ };
+ bool parse_absb_17(SSR::Data_Source_Interface* src, SSR::P_S mode_s_msg, JSON& msg_json,
+ std::optional base_station_pos, CPR::D max_speed_m_s, CPR::Time air_pos_time_out, CPR::Time surface_pos_time_out) {
+ bool new_create;
+ std::shared_ptr a = src->get_aircraft(mode_s_msg->icao);
+ if (!a) {
+ a = src->create_aircraft(mode_s_msg->icao);
+ }
+ Aircraft_Info& info = *a;
+ info.refresh_pos(false);
+ std::string& msg_bin = mode_s_msg->msg_bin;
+ MLAT_timestamp* mlat_timestamp = &mode_s_msg->mlat_timestamp;
+ Parse(base2, ADS_B_base)
+ int tc = type_code(msg_bin);
+ if (tc >= 1 && tc <= 4) {
+ Parse(t, BDS08_id)
+ } else if (tc >= 5 && tc <= 8) {
+ Parse_no_json(t, BDS06_surface_position)
+ info.refresh_pos(true);
+ t.base_station_pos = base_station_pos;
+ auto tp = t.parse_message(mode_s_msg, mode_s_msg->time().abs_sec(), max_speed_m_s, surface_pos_time_out, cpr_cb);
+ if (tp.has_value()) {
+ auto t2 = t.odd_msg;
+ Position_Info p(tp.value(), info.altitude_meter().value_or(0));
+ info.surface_pos_track_list.push(p);
+ info.mlat = false;
+ parse_pos_call_back(&info, mode_s_msg, true);
+ msg_json.append_list(t.toJson().children);
+ }
+ } else if ((tc >= 9 && tc <= 18) || (tc >= 20 && tc <= 22)) {
+ Parse_no_json(t, BDS05_airborne_position)
+ info.refresh_pos(true);
+ if (info.absb_version == 0 || info.absb_version == 1) {
+ Parse(t2, BDS05_airborne_Position_v01)
+ } else if (info.absb_version == 2) {
+ Parse(t2, BDS05_airborne_Position_v2)
+ }
+ using namespace std::chrono;
+ auto tp = t.parse_message(mode_s_msg, mode_s_msg->time().abs_sec(), max_speed_m_s, air_pos_time_out, cpr_cb);
+ if (tp.has_value()) {
+ auto alt = t.get_alt_meter();
+ Position_Info p(tp.value(), alt);
+ info.air_pos_track_list.push(p);
+ info.mlat = false;
+ parse_pos_call_back(&info, mode_s_msg, false);
+ msg_json.append_list(t.toJson().children);
+ }
+ } else if (tc == 19) {
+ //速度
+ Parse(t, BDS09_Base)
+ int subType = get_bin<37, 3>(msg_bin);
+ if (subType == 1 || subType == 2) {
+ Parse(s12, ground_speed)
+ } else if (subType == 3 || subType == 4) {
+ Parse(s34, air_speed)
+ } else {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::Unknown_tc, nullptr, VAR_STR_1(subType) + "超出范围 tc == 19 error! ",
+ {}, nullptr, mode_s_msg);
+ }
+ if (info.absb_version == 0) {
+ Parse(v0, BDS09_v0)
+ } else if (info.absb_version == 1 || info.absb_version == 2) {
+ Parse(v12, BDS09_v12)
+ }
+ } else if (tc == 28) {
+ Parse(t, BDS61)
+ int st = t.get_sub_type();
+ if (st == 1) {
+ Parse(st1, BDS61_mode_a)
+ }
+ if (st == 2) {
+ Parse(st2, BDS61_mode_TCAS_ACAS_RA_Broadcast)
+ }
+ } else if (tc == 29) {
+ Parse(t, BDS62)
+ auto st = t.get_sub_type();
+ if (st == 0) {
+ Parse(tv1, BDS62_ver1)
+ }
+ if (st == 1) {
+ Parse(tv2, BDS62_ver2)
+ }
+ } else if (tc == 31) {
+ Parse(t, BDS65_Base)
+ int st = get_bin<37, 3>(msg_bin);
+ int ver = t.get_ADS_B_version();
+ info.absb_version = ver;
+ if (st == 0) {
+ Parse(t2, BDS65_Airborne)
+ } else if (st == 1) {
+ Parse(t2, BDS65_Surface)
+ }
+ if (ver == 1) {
+ Parse(t2, BDS65_v1)
+ } else if (ver == 2) {
+ Parse(t2, BDS65_v2)
+ }
+ } else {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::Unknown_tc, nullptr, "commb bds not one",
+ {}, nullptr, mode_s_msg);
+ }
+ return true;
+ }
+ bool parse_Message_commb(SSR::Data_Source_Interface* src, const std::string& BDS, SSR::P_S mode_s_msg,
+ JSON& msg_json) {
+ std::string& msg = mode_s_msg->msg_bin;
+ Downlink_Format& df = mode_s_msg->df;
+ bool new_create;
+ std::shared_ptr a = src->get_aircraft(mode_s_msg->icao);
+ if (!a) {
+ a = src->create_aircraft(mode_s_msg->icao);
+ }
+ Aircraft_Info& info = *a;
+ Parse(rb, Reply_Base_builder)
+ if (df == Downlink_Format::Comm_B_Altitude_Reply_20) {
+ Parse(alt, alt)
+ }
+ if (df == Downlink_Format::Comm_B_Identity_Reply_21) {
+ Parse(id, id)
+ }
+ if (BDS == "10") {
+ Parse(t, BDS10)
+ } else if (BDS == "17") {
+ Parse(t, BDS17)
+ } else if (BDS == "20") {
+ Parse(t, BDS20)
+ } else if (BDS == "30") {
+ Parse(t, BDS30)
+ ACAS_SubType st = t.parse_sum(msg);
+ msg_json.append({"ACAS_SubType st", to_string(st)});
+ switch (st) {
+ case ACAS_SubType::NO_RA: break;
+ case ACAS_SubType::One_threat: {
+ Parse(t2, one)
+ break;
+ }
+ case ACAS_SubType::Mult_below_above:
+ case ACAS_SubType::Mult_same_direction: {
+ Parse(t2, muti)
+ break;
+ }
+ }
+ Threat_Type_Indicator ti = t.get_threat_Type_Indicator();
+ msg_json.append({"Threat_Type_Indicator",to_string(ti)});
+ switch (ti) {
+ case Threat_Type_Indicator::No_Identity_Data: break;
+ case Threat_Type_Indicator::Mode_S_Transponder_Address: {
+ Parse(t2, transponder_address)
+ break;
+ }
+ case Threat_Type_Indicator::Altitude_Range_Bearing: {
+ Parse(t2, Altitude_Range_Bearing)
+ break;
+ }
+ }
+ } else if (BDS == "40") {
+ Parse(t, BDS40)
+ } else if (BDS == "50") {
+ Parse(t, BDS50)
+ } else if (BDS == "60") {
+ Parse(t, BDS60)
+ } else if (BDS == "44") {
+ Parse(t, BDS44)
+ } else if (BDS == "45") {
+ Parse(t, BDS45)
+ }
+ return true;
+ }
+ bool parse_mode_s_bin(Data_Source_Interface* src, P_S mode_s_msg, std::optional base_station_pos, CPR::D max_speed_m_s, CPR::Time air_pos_time_out, CPR::Time surface_pos_time_out) {
+ auto& msg_hex = mode_s_msg->msg_hex;
+ auto& msg = mode_s_msg->msg_bin;
+ auto& df = mode_s_msg->df;
+ auto& icao = mode_s_msg->icao;
+ JSON msg_json = JSON::object();
+ bool ok = true;
+ if (df == Downlink_Format::Extended_Squitter_17) {
+ checkLength(28)
+ if (!with_PI::check_crc(msg, icao)) {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::CRC_Error, nullptr,
+ "parse_absb_17 crc_error", {}, nullptr, mode_s_msg);
+ return false;
+ }
+ ok = parse_absb_17(src, mode_s_msg, msg_json, base_station_pos, max_speed_m_s, air_pos_time_out, surface_pos_time_out);
+ } else if (df == Downlink_Format::Comm_B_Altitude_Reply_20 || df == Downlink_Format::Comm_B_Identity_Reply_21) {
+ checkLength(28)
+ if (!src->get_aircraft(icao)) {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::ICAO_Error, nullptr, "",
+ {}, nullptr, mode_s_msg);
+ return false;
+ }
+ std::vector bds_list = infer2(msg, true);
+ if (bds_list.empty()) {
+ msg_json.append({"bds", "bds_empty"});
+ std::string bds_list_str;
+ for (auto& bds : bds_list) {
+ bds_list_str += "_" + bds;
+ }
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::Cannot_Choose_BDS, nullptr, "commb bds zero",
+ {}, nullptr, mode_s_msg);
+ return false;
+ }
+ if (bds_list.size() > 1) {
+ std::string that;
+ for (const std::string& bds : bds_list) {
+ that.append(bds + "_");
+ }
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::More_than_one_BDS, nullptr, "commb bds not one",
+ {}, nullptr, mode_s_msg);
+
+ }
+ std::string BDS = bds_list[0];
+ if (!with_AP::check_crc(msg, icao, BDS)) {
+ msg_json.append({"crc", "invalid crc"});
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::CRC_Error, nullptr, "commb_crc",
+ {}, nullptr, mode_s_msg);
+ return false;
+ }
+ ok = parse_Message_commb(src, BDS, mode_s_msg, msg_json);
+ } else if (df == Downlink_Format::Surveillance_Altitude_Reply_4 || df ==
+ Downlink_Format::Surveillance_Identity_Reply_5) {
+ checkLength(14)
+ if (!src->get_aircraft(icao)) {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::ICAO_Error, nullptr, "",
+ {}, nullptr, mode_s_msg);
+ return false;
+ }
+ if (!with_AP::check_crc(msg, icao)) {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::CRC_Error, nullptr, "Surveillance crc_error",
+ {},nullptr, mode_s_msg);
+ return false;
+ }
+
+ std::shared_ptr a = src->get_aircraft(mode_s_msg->icao);
+ Aircraft_Info& info = *a;
+ Parse(rb, Reply_Base_builder)
+ if (df == Downlink_Format::Surveillance_Altitude_Reply_4) {
+ Parse(alt, alt)
+ }
+ if (df == Downlink_Format::Surveillance_Identity_Reply_5) {
+ Parse(id, id)
+ }
+ } else if (df == Downlink_Format::All_Call_Reply_11) {
+ checkLength(14)
+ if (!src->get_aircraft(icao)) {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::ICAO_Error, nullptr, "",
+ {}, nullptr, mode_s_msg);
+ return false;
+ }
+ // if (!with_PI::check_crc(msg, icao, "")) {
+ // if (error_call_back) error_call_back(info, "All_Call_Reply crc_error", mode_s_msg);
+ // return false;
+ // }
+ // https://mode-s.org/1090mhz/content/mode-s/1-basics.html
+
+ std::shared_ptr a = src->get_aircraft(mode_s_msg->icao);
+ if (a) {
+ Aircraft_Info& info = *a;
+ Parse(all_call_reply, all_call_reply)
+ }
+ } else if (df == Downlink_Format::Short_Air_Air_Surveillance_0) {
+ checkLength(14)
+ if (!src->get_aircraft(icao)) {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::ICAO_Error, nullptr, "",
+ {}, nullptr, mode_s_msg);
+ return false;
+ }
+ if (!with_AP::check_crc(msg, icao)) {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::CRC_Error, nullptr,
+ "Short_Air_Air_Surveillance crc_error", {}, nullptr, mode_s_msg);
+ return false;
+ }
+ std::shared_ptr a = src->get_aircraft(mode_s_msg->icao);
+ if (a) {
+ Aircraft_Info& info = *a;
+ Parse(s_acas, short_ACAS)
+ }
+ } else if (df == Downlink_Format::Long_Air_Air_Surveillance_16) {
+ checkLength(28)
+ if (!src->get_aircraft(icao)) {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::ICAO_Error, nullptr, "",
+ {}, nullptr, mode_s_msg);
+ return false;
+ }
+ if (!with_AP::check_crc(msg, icao)) {
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::CRC_Error, nullptr,
+ "Long_Air_Air_Surveillance crc_error", {}, nullptr, mode_s_msg);
+ return false;
+ }
+ std::shared_ptr a = src->get_aircraft(mode_s_msg->icao);
+ if (a) {
+ Aircraft_Info& info = *a;
+ Parse(s_acas, long_ACAS)
+ if (ACAS_T::Parser_VDS_3_0_Coordination_Reply::is(msg)) {
+ Parse(base, VDS_3_0_Base)
+ if (ACAS_T::Parser_VDS_3_0_ARA1::is(msg)) {
+ Parse(base1, VDS_3_0_1)
+ }
+ if (ACAS_T::Parser_VDS_3_0_ARA2::is(msg)) {
+ Parse(base2, VDS_3_0_2)
+ }
+ }
+ }
+ } else {
+ // 没找到能解的df
+ if (parse_call_back) parse_call_back(Parse_Call_Back_Type::Unknown_DF, nullptr, "unknown df error", {}, nullptr,
+ mode_s_msg);
+ return false;
+ }
+ std::shared_ptr a = src->get_aircraft(mode_s_msg->icao);
+ if (a) {
+ ++a->times;
+ }
+ parse_ok_json(a.get(), mode_s_msg, msg_json);
+ return ok;
+ }
+
+
+
+bool Monitor_Mode_ACS_Message_Num = false;
+struct Live_Report {
+ explicit Live_Report(const std::string& name) : name(name) {}
+ void add() {
+ ++live_num;
+ if (l.test()) {
+ report();
+ return;
+ }
+ }
+ void remove() {
+ --live_num;
+ if (l.test()) {
+ report();
+ return;
+ }
+ // if (live_num < 10) {
+ // report();
+ // }
+ }
+ void report() {
+ std::ostringstream oss;
+ oss << "[" << name << "]: " << total++;
+ oss << " current_num==" << live_num << std::endl;
+ std::cout << oss.str() << std::flush;
+ }
+protected:
+ std::string name = "null";
+ Frequency_Limit l;
+ std::atomic live_num{}; //存活的对象数量
+ std::atomic total{};
+};
+Live_Report ac_mode("ac");
+Live_Report s_mode("s");
+Live_Report plane("plane");
+// 以字节为单位
+// 1 + 1 + 6 + 1 + 2/7/14
+// 1a + type time_stamp signal_level data
+Mode_Msg::Mode_Msg(const std::shared_ptr& source, const std::string& packet) : Msg(source, packet) {
+ mlat_timestamp = MLAT_timestamp(packet.substr(2, 6));
+ signal_level = packet[8];
+ std::string memory = packet.substr(9);
+ msg_hex = mem2hex(memory);
+ msg_bin = hex2bin(msg_hex);
+ if (mlat_timestamp.daysec == 0 && mlat_timestamp.nanosec == 0) {
+ std::time_t tp = std::time(nullptr);
+ mlat_timestamp.daysec = tp % (3600 * 24);
+ }
+}
+Mode_Msg::~Mode_Msg() {}
+Mode_AC_Msg::Mode_AC_Msg(const std::shared_ptr& source, const std::string& packet) : Mode_Msg(
+ source, packet) {
+ if (packet.size() != AC_len) {
+ std::string log = "0x31 Mode_S_Msg 长度错误!" + packet;
+ std::cout << log << std::endl;
+ mode_s_logger->error("", {}, log);
+ Psc::fail_fast();
+ }
+ if (Monitor_Mode_ACS_Message_Num) {
+ ac_mode.add();
+ }
+}
+Mode_AC_Msg::~Mode_AC_Msg() {
+ if (Monitor_Mode_ACS_Message_Num) {
+ ac_mode.remove();
+ }
+}
+Mode_S_Msg::Mode_S_Msg(const std::shared_ptr& source,
+ const std::string& packet) : Mode_Msg(source, packet) {
+ if (type == S7) {
+ if (packet.size() != S7_len) {
+ std::string log = "0x32 Mode_S_Msg 长度错误!" + packet;
+ std::cout << log << std::endl;
+ mode_s_logger->error("", {}, log);
+ Psc::fail_fast();
+ }
+ }
+ if (type == S14) {
+ if (packet.size() != S14_len) {
+ std::string log = "0x33 Mode_S_Msg 长度错误!" + packet;
+ std::cout << log << std::endl;
+ mode_s_logger->error("", {}, log);
+ Psc::fail_fast();
+ }
+ }
+ df = decode_df(hex2bin(msg_hex.substr(0, 2)));
+ icao = SSR::decode_icao(msg_bin);
+ if (Monitor_Mode_ACS_Message_Num) {
+ s_mode.add();
+ }
+}
+Mode_S_Msg::~Mode_S_Msg() {
+ if (Monitor_Mode_ACS_Message_Num) {
+ s_mode.remove();
+ }
+}
+
+
+
+
+Psc::JSON POS_List::get_last_array_json(std::uint64_t last_seq) {
+ std::lock_guard g(mtx.mtx);
+
+ Psc::JSON ret = Psc::JSON::object();
+ Psc::JSON arr = Psc::JSON::array();
+
+ std::uint64_t cur_seq = seq;
+
+
+ if (last_seq >= cur_seq) {
+ ret.append({"sta_seq", last_seq});
+ ret.append({"end_seq", cur_seq});
+ ret.append({"size", 0});
+ ret.append({"list", arr});
+ return ret;
+ }
+
+ std::uint64_t delta = cur_seq - last_seq;
+ std::uint64_t available = std::min(delta, count);
+
+ for (std::uint64_t i = available; i > 0; --i) {
+ std::size_t idx = (head + max_size - i) % max_size;
+ auto cur = buf[idx].to_json();
+ cur.append({"idx", idx});
+ arr.append(cur);
+ }
+
+ ret.append({"sta_seq", last_seq});
+ ret.append({"end_seq", cur_seq});
+ ret.append({"size", arr.children.size()});
+ ret.append({"list", arr});
+ return ret;
+}
+std::string POS_List::to_string() {
+ return get_last_array_json(0).to_json_string();
+}
+Aircraft_Info::Aircraft_Info(std::string icao) : icao(std::move(icao)) {
+ if (Monitor_Mode_ACS_Message_Num) {
+ plane.add();
+ }
+}
+Aircraft_Info::~Aircraft_Info() {
+ if (Monitor_Mode_ACS_Message_Num) {
+ plane.remove();
+ }
+}
+}
\ No newline at end of file
diff --git a/SSR/Aircraft_Info.h b/SSR/Aircraft_Info.h
new file mode 100644
index 0000000..776611a
--- /dev/null
+++ b/SSR/Aircraft_Info.h
@@ -0,0 +1,311 @@
+#pragma once
+#include "../../Core/Core/system/export.h"
+#include "ACAS/ACAS.h"
+#include "ADS_B/ADS_B.h"
+#include "Commb/Commb.h"
+#include "Mode_S/Mode_S.h"
+#include "Msg.h"
+#include "convert/DataOutputFormats.h"
+#include
+
+namespace SSR {
+
+#define GET_PRE(name) \
+std::lock_guard lock(name.mtx.mtx); \
+if (!name.value.has_value()) \
+{ \
+return std::nullopt; \
+} \
+auto& w = name.value.value();
+// #define EJ2(NAME) \
+// if (NAME.value.has_value()) ret.append(Psc::Json(STRINGIFY(timestamp_##NAME), NAME.time)); \
+// ret.append(NAME.value.has_value() ? Psc::Json(#NAME, NAME.value.value().toJson()) : Psc::Json(#NAME, nullptr));
+template
+void d(Psc::JSON& ret, T& t, const std::string& name) {
+ std::lock_guard g(t.mtx.mtx);
+ if (!t.value.has_value()) {
+ ret.append(Psc::JSON(name, nullptr));
+ return;
+ }
+ auto tt = t.value.value().toJson();
+ tt.prepend(Psc::JSON("time", Psc::utc_2_local_time(t.time, "%H:%M:%S")));
+ tt.prepend(Psc::JSON("总数", t.sum));
+ tt.prepend(Psc::JSON("每秒数量", t.per_second_num));
+ ret.append({name, tt});
+}
+template
+struct Time {
+ long long time = 0;
+ RET value;
+ size_t sum{};
+ size_t per_second_num{};
+ NoneCopyLock mtx;
+};
+
+#define EJ2(NAME) d(ret, NAME, #NAME);
+class Aircraft_Info {
+public:
+ explicit Aircraft_Info(std::string icao);
+ virtual ~Aircraft_Info();
+
+ void push_all_bds_info(Psc::JSON& ret) {
+ EJ2(ADS_B_base)
+ EJ2(BDS08_id)
+ EJ2(BDS06_surface_position)
+ EJ2(BDS05_airborne_position)
+ EJ2(BDS05_airborne_Position_v01)
+ EJ2(BDS05_airborne_Position_v2)
+ EJ2(ground_speed)
+ EJ2(air_speed)
+ EJ2(BDS09_v0)
+ EJ2(BDS09_v12)
+ EJ2(BDS65_Base)
+ EJ2(BDS65_Airborne)
+ EJ2(BDS65_Surface)
+ EJ2(BDS65_v1)
+ EJ2(BDS65_v2)
+ EJ2(all_call_reply)
+ EJ2(Reply_Base_builder)
+ EJ2(alt)
+ EJ2(id)
+ EJ2(BDS20)
+ EJ2(BDS10)
+ EJ2(BDS17)
+ EJ2(BDS30)
+ EJ2(muti)
+ EJ2(one)
+ EJ2(transponder_address)
+ EJ2(Altitude_Range_Bearing)
+ EJ2(BDS40)
+ EJ2(BDS50)
+ EJ2(BDS60)
+ EJ2(BDS44)
+ EJ2(BDS45)
+ EJ2(short_ACAS)
+ EJ2(long_ACAS)
+ EJ2(VDS_3_0_Base)
+ EJ2(VDS_3_0_1)
+ EJ2(VDS_3_0_2)
+ }
+
+
+ virtual Psc::JSON toJson() {
+ Psc::JSON ret = Psc::JSON::object();
+ Ret_J(icao)
+ ret.append({"每秒位置数", get_pest()});
+ ret.append({"飞机位置轨迹点数", air_pos_track_list.size()});
+ ret.append({"地面位置轨迹点数", surface_pos_track_list.size()});
+ ret.append({"信号强度", signal_level});
+ ret.append({"时间", Psc::utc_2_local_time(timestamp)});
+ Psc::JSON j("多点定位数据源", mlat);
+ ret.append({"多点定位数据源", mlat});
+ push_all_bds_info(ret);
+ return ret;
+ }
+
+
+ POS_List air_pos_track_list;
+ POS_List surface_pos_track_list;
+ std::string icao;
+ std::atomic mlat = false;
+ time_t timestamp = std::time(nullptr);
+
+ int get_pest() {
+ std::lock_guard lock(pest_mutex.mtx);
+ return pest;
+ }
+ void refresh_pos(bool pos) {
+ std::lock_guard lock(pest_mutex.mtx);
+ auto cur = std::time(nullptr);
+ if (cur == pest_timestamp) {
+ if (pos) {
+ pest++;
+ }
+ } else {
+ pest = 0;
+ pest_timestamp = cur;
+ }
+ }
+ unsigned char absb_version = 0;
+ MLAT_timestamp mlat_timestamp;
+ int signal_level{}; // signal level in dBm
+ std::optional SIL() {
+ GET_PRE(BDS65_Base)
+ return w.get_SIL();
+ }
+ std::optional NACp() {
+ GET_PRE(BDS65_Base)
+ return w.get_NACp_4();
+ }
+ std::optional ADS_B_Ver() {
+ GET_PRE(BDS65_Base)
+ return w.get_ADS_B_version();
+ }
+ std::optional wind_speed() {
+ GET_PRE(BDS44)
+ return w.wind_speed;
+ }
+ std::optional temperature() {
+ GET_PRE(BDS44)
+ return static_cast(w.temperature);
+ }
+ std::optional wind_direction() {
+ GET_PRE(BDS44)
+ return w.wind_direction;
+ }
+
+
+ // 航班号
+ RET flight() {
+ GET_PRE(BDS08_id)
+ return w.get_call_sign();
+ }
+
+
+
+ RET alart() {
+ GET_PRE(BDS05_airborne_position)
+ Surveillance_Status s = w.get_surveillance_status();
+ return s == Surveillance_Status::TemporaryAlert || s == Surveillance_Status::PermanentAlert;
+ }
+
+ // 空中交通管制(ATC)用来识别飞机的四位数代码
+ // Squawk 代码有很多用途,包括特定的安全指令,如紧急情况时使用的应答机代码(如7500表示劫机,7700表示紧急状况等)
+ RET squawk() {
+ GET_PRE(id)
+ if (!id.value.has_value()) {
+ return std::nullopt;
+ }
+ return id.value.value().get_ATC_Squawk();
+ }
+ RET bds20_call_sign() {
+ GET_PRE(BDS20)
+ return BDS20.value.value().get_call_sign();
+ }
+ RET is_on_ground() {
+ GET_PRE(Reply_Base_builder)
+ if (w.get_flight_status() == Flight_Status::alert_on_ground || w.get_flight_status() ==
+ Flight_Status::no_alert_on_ground) {
+ return true;
+ }
+ return false;
+ }
+ RET speed() {
+ GET_PRE(ground_speed)
+ return w.get_speed() * aero::kts;
+ }
+ // ft/min
+ RET vertical_rate() {
+ GET_PRE(BDS09_Base)
+ auto v = w.get_vertical_rate();
+ if (!v.has_value()) return std::nullopt;
+ return v.value() * aero::fpm;
+ }
+
+
+ RET pos() {
+ // GET_PRE(BDS05_airborne_position)
+ // auto& it = BDS05_airborne_position.value.value();
+ // if (it.get_lat().has_value() && it.get_lon().has_value()) {
+ // return CPR::Position{it.get_lat().value(), it.get_lon().value()};
+ // }
+ if (air_pos_track_list.empty()) return std::nullopt;
+ return air_pos_track_list.last();
+ }
+ RET select_heading() {
+ GET_PRE(BDS60)
+ return w.get_magnetic_heading();
+ }
+ RET air_magnetic_heading() {
+ GET_PRE(air_speed)
+ return w.get_magnetic_heading();
+ }
+ RET surface_magnetic_heading() {
+ GET_PRE(ground_speed)
+ return w.get_magnetic_heading();
+ }
+ RET altitude_meter() {
+ GET_PRE(BDS05_airborne_position)
+ return w.get_alt_meter();
+ }
+ RET vortex_type() {
+ GET_PRE(BDS08_id)
+ return w.get_vortex_type();
+ }
+ RET get_airspeed() {
+ GET_PRE(air_speed)
+ return w;
+ }
+ RET get_speed_base() {
+ GET_PRE(BDS09_Base)
+ return w;
+ }
+ // 用于给外部输出统计信息
+ // info, field_name, &t, msg
+ std::atomic times = 0;
+ time_t pest_timestamp{};
+ int pest{}; // 每秒位置数
+ NoneCopyLock pest_mutex;
+ Time ADS_B_base;
+ // 身份模块
+ Time BDS08_id;
+ // 位置模块
+ Time BDS06_surface_position;
+ Time BDS05_airborne_position;
+ Time BDS05_airborne_Position_v01;
+ Time BDS05_airborne_Position_v2;
+ // 速度模块
+ Time BDS09_Base;
+ Time ground_speed;
+ Time air_speed;
+ Time BDS09_v0;
+ Time BDS09_v12;
+ // 版本解码
+ Time BDS65_Base;
+ Time BDS65_Airborne;
+ Time BDS65_Surface;
+ Time BDS65_v1;
+ Time BDS65_v2;
+ // mode-s 其他
+ Time all_call_reply;
+ Time Reply_Base_builder;
+ Time alt;
+ Time id;
+ Time BDS20;
+ Time BDS10;
+ Time BDS17;
+ Time BDS30;
+ Time muti;
+ Time one;
+ Time transponder_address;
+ Time Altitude_Range_Bearing;
+ Time BDS40;
+ Time BDS50;
+ Time BDS60;
+ Time BDS44;
+ Time BDS45;
+ Time BDS61;
+ Time BDS61_mode_a;
+ Time BDS61_mode_TCAS_ACAS_RA_Broadcast;
+ Time BDS62;
+ Time BDS62_ver1;
+ Time BDS62_ver2;
+ Time short_ACAS;
+ Time long_ACAS;
+ Time VDS_3_0_Base;
+ Time VDS_3_0_1;
+ Time VDS_3_0_2;
+ void update(const std::shared_ptr& mode_s_msg) {
+ MLAT_timestamp* t = &mode_s_msg->mlat_timestamp;
+ this->mlat_timestamp = *t;
+ this->signal_level = mode_s_msg->signal_level;
+ this->timestamp = std::time(nullptr);
+ }
+
+};
+
+
+
+}
+
+
diff --git a/SSR/CPR/CPR.cpp b/SSR/CPR/CPR.cpp
new file mode 100644
index 0000000..2cf124b
--- /dev/null
+++ b/SSR/CPR/CPR.cpp
@@ -0,0 +1,379 @@
+#include "CPR.h"
+#include
+#include
+#include
+#include
+#include
+
+#include "SSR/global.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+namespace SSR {
+namespace CPR {
+
+ std::string Position::to_string() const {
+ return "[" + std::to_string(lat) + "," + std::to_string(lon) + "]";
+ }
+
+ // D MOD(D x, D y) {
+ // if (y == 0) {
+ // std::cerr << "Error: Division by zero" << std::endl;
+ // return 0;
+ // }
+ // return x - y * std::floor(x / y);
+ // }
+ D MOD(D x, D y) {
+ if (y == 0) {
+ std::cerr << "Error: Division by zero" << std::endl;
+ return 0;
+ }
+ return x - y * std::floor(x / y); // 否则按标准模运算
+ }
+
+ I NL2(D lat) {
+ auto abs_lat = std::abs(lat);
+ if (abs_lat < 1e-6) return 59;
+ if (abs_lat == 87) return 2;
+ if (abs_lat > 87) return 1;
+ D a = 1 - std::cos(M_PI / (2 * NZ));
+ auto b = std::cos(M_PI / 180 * abs_lat);
+ D nl = 2 * M_PI / std::acos(1 - a / (b * b));
+ return floor(nl);
+ }
+
+
+ I NL(D lat) {
+ if (lat > 90.0) lat -= 360.0;
+ if (lat < 0) lat = -lat; /* Table is simmetric about the equator. */
+ // if (lat > 90 + 0.1) {
+ // Log_Type t({}, {{"POS", LOG_POS}});
+ // mode_s_logger->error("nl error!", t, "lat 居然超过90度!");
+ // std::cout << "lat: " << lat << std::endl;
+ // exit(-1011);
+ // }
+ if (lat < 10.47047130) return 59;
+ if (lat < 14.82817437) return 58;
+ if (lat < 18.18626357) return 57;
+ if (lat < 21.02939493) return 56;
+ if (lat < 23.54504487) return 55;
+ if (lat < 25.82924707) return 54;
+ if (lat < 27.93898710) return 53;
+ if (lat < 29.91135686) return 52;
+ if (lat < 31.77209708) return 51;
+ if (lat < 33.53993436) return 50;
+ if (lat < 35.22899598) return 49;
+ if (lat < 36.85025108) return 48;
+ if (lat < 38.41241892) return 47;
+ if (lat < 39.92256684) return 46;
+ if (lat < 41.38651832) return 45;
+ if (lat < 42.80914012) return 44;
+ if (lat < 44.19454951) return 43;
+ if (lat < 45.54626723) return 42;
+ if (lat < 46.86733252) return 41;
+ if (lat < 48.16039128) return 40;
+ if (lat < 49.42776439) return 39;
+ if (lat < 50.67150166) return 38;
+ if (lat < 51.89342469) return 37;
+ if (lat < 53.09516153) return 36;
+ if (lat < 54.27817472) return 35;
+ if (lat < 55.44378444) return 34;
+ if (lat < 56.59318756) return 33;
+ if (lat < 57.72747354) return 32;
+ if (lat < 58.84763776) return 31;
+ if (lat < 59.95459277) return 30;
+ if (lat < 61.04917774) return 29;
+ if (lat < 62.13216659) return 28;
+ if (lat < 63.20427479) return 27;
+ if (lat < 64.26616523) return 26;
+ if (lat < 65.31845310) return 25;
+ if (lat < 66.36171008) return 24;
+ if (lat < 67.39646774) return 23;
+ if (lat < 68.42322022) return 22;
+ if (lat < 69.44242631) return 21;
+ if (lat < 70.45451075) return 20;
+ if (lat < 71.45986473) return 19;
+ if (lat < 72.45884545) return 18;
+ if (lat < 73.45177442) return 17;
+ if (lat < 74.43893416) return 16;
+ if (lat < 75.42056257) return 15;
+ if (lat < 76.39684391) return 14;
+ if (lat < 77.36789461) return 13;
+ if (lat < 78.33374083) return 12;
+ if (lat < 79.29428225) return 11;
+ if (lat < 80.24923213) return 10;
+ if (lat < 81.19801349) return 9;
+ if (lat < 82.13956981) return 8;
+ if (lat < 83.07199445) return 7;
+ if (lat < 83.99173563) return 6;
+ if (lat < 84.89166191) return 5;
+ if (lat < 85.75541621) return 4;
+ if (lat < 86.53536998) return 3;
+ if (lat < 87.00000000) return 2;
+ else return 1;
+ }
+
+
+ std::optional> global_decode(I YZ0, I YZ1, I XZ0, I XZ1, I _2, D r) {
+ D p2 = 2 << (_2 - 1);
+ D p_YZ0 = static_cast(YZ0)/p2;
+ D p_YZ1 = static_cast(YZ1)/p2;
+ D p_XZ0 = static_cast(XZ0)/p2;
+ D p_XZ1 = static_cast(XZ1)/p2;
+ D j_pure = 59.0 * p_YZ0 - 60.0 * p_YZ1;
+ D j = floor(j_pure + 0.5);
+ D Dlat_0 = r / 60.0;
+ D Dlat_1 = r / 59.0;
+ D Rlat_0 = Dlat_0 * (MOD(j, 60 - 0) + p_YZ0);
+ D Rlat_1 = Dlat_1 * (MOD(j, 60 - 1) + p_YZ1);
+ bool southern0 = Rlat_0 > 270.0 && Rlat_0 < 360.0;
+ bool southern1 = Rlat_1 > 270.0 && Rlat_1 < 360.0;
+ bool northern0 = Rlat_0 > 0.0 && Rlat_0 < 90.0;
+ bool northern1 = Rlat_1 > 0.0 && Rlat_1 < 90.0;
+ if (northern0 && northern1) {
+ } else if (southern0 && southern1) {
+ Rlat_0 -= 360.0;
+ Rlat_1 -= 360.0;
+ } else {
+ Log_Type type({}, {{"POS", LOG_POS}});
+ mode_s_logger->debug("", type, VAR_STR_7(YZ0, YZ1, XZ0, XZ1, _2, r, j));
+ return std::nullopt;
+ }
+ I nl0 = NL(Rlat_0);
+ I nl1 = NL(Rlat_1);
+ if(nl0 != nl1) {
+ return std::nullopt;
+ }
+ D nl = static_cast(nl0);
+ D ni_0 = nl;
+ D ni_1 = (nl0 == 1 ? 1 : nl - 1);
+ D m_pure = p_XZ0 * ni_1 - p_XZ1 * ni_0;
+ D m = floor(m_pure + 0.5);
+ D Dlon_0 = r / ni_0;
+ D Dlon_1 = r / ni_1;
+ D Rlon_0 = Dlon_0 * (MOD(m, ni_0) + p_XZ0);
+ D Rlon_1 = Dlon_1 * (MOD(m, ni_1) + p_XZ1);
+ return std::tuple{Position{Rlat_0, Rlon_0}, Position{Rlat_1, Rlon_1}};
+ }
+
+
+
+ POS locale_decode(D lat_s, D lon_s, I YZi, I XZi, I i, I _2, D r) {
+ D p2 = 2 << (_2 - 1);
+ D p_YZ = static_cast(YZi)/p2;
+ D p_XZ = static_cast(XZi)/p2;
+ D Dlat_i = r / static_cast(4 * NZ - i);
+ I j = floor(lat_s / Dlat_i) + floor(0.5 + MOD(lat_s, Dlat_i)/Dlat_i - p_YZ);
+ D Rlat_i = Dlat_i * (static_cast(j) + p_YZ);
+ I nl = NL(Rlat_i);
+ I nl_s = NL(lat_s);
+ if(nl != nl_s) {
+ return std::nullopt;
+ }
+ D Dlon_i{};
+ if(nl - i > 0){
+ Dlon_i = r / static_cast((nl - i == 0) ? 1 : (nl - i));
+ } else if(nl - i == 0) {
+ Dlon_i = r;
+ } else {
+ // 不可能到达这
+ }
+ I m = floor(lon_s/Dlon_i) + floor(0.5 + MOD(lon_s, Dlon_i)/Dlon_i - p_XZ);
+ D Rlon_i = Dlon_i * (static_cast(m) + p_XZ);
+ return Position{Rlat_i, Rlon_i};
+ }
+
+ std::tuple encode(D lat, D lon, I Nb, I i) {
+ D p2 = 2 << (Nb - 1);
+ D Dlat_i = 360.0 / static_cast(4 * NZ - i);
+ if (lat < 0) {
+ lat += 360;
+ }
+ if (lon < 0) {
+ lon += 360.0;
+ }
+ D YZi = floor(p2 * MOD(lat, Dlat_i)/Dlat_i + 0.5);
+ D Rlat_i = Dlat_i * (YZi/p2 + floor(lat/Dlat_i));
+ I nl = NL(Rlat_i);
+ D Dlon_i{};
+
+ if(nl - i > 0){
+ auto ii = static_cast(std::max((I)1, nl - i));
+ Dlon_i = 360.0 / ii;
+ } else if(nl - i == 0){
+ Dlon_i = 360.0;
+ } else {
+ // 不可能到达这
+ }
+ D XZi = floor(p2 * MOD(lon, Dlon_i)/Dlon_i + 0.5);
+ return {static_cast(YZi), static_cast(XZi)};
+ }
+
+ std::tuple get(const std::string& msg_bin){
+ std::string mb = msg_bin.substr(32);
+ auto YZ = bin2(mb.substr(22, 17));
+ auto XZ = bin2(mb.substr(39, 17));
+ CPR::I i = mb[21] - '0';
+ return {YZ, XZ, i};
+ }
+
+
+
+ std::string lat_lon_airborne_34(double latitude, double longitude, CPR::Frame cpr_format) {
+ auto [YZ, XZ] = CPR::encode(latitude, longitude, 17, cpr_format);
+ return std::bitset<17>(YZ).to_string() + std::bitset<17>(XZ).to_string();
+ }
+
+
+ std::optional airborne_position(const std::string& msg0, const std::string& msg1, Time t0, Time t1) {
+ auto [YZ0, XZ0, i0] = CPR::get(msg0);
+ auto [YZ1, XZ1, i1] = CPR::get(msg1);
+ if (i0 == i1){
+ return std::nullopt;
+ }
+ if(i0 == 1 && i1 == 0){
+ std::swap(YZ0, YZ1);
+ std::swap(XZ0, XZ1);
+ std::swap(t0, t1);
+ std::swap(i0, i1);
+ }
+ auto poses = CPR::global_decode(YZ0, YZ1, XZ0, XZ1, 17, 360.0);
+ if(!poses.has_value()) return std::nullopt;
+ auto [pos0, pos1] = poses.value();
+
+ std::string info = pos0.to_string() + " @@@@ " + pos1.to_string();
+
+ // std::cout << info << std::endl;
+ mode_s_logger->debug("CPR_global_decode", {}, info);
+ return (t0 > t1) ? pos0 : pos1;
+ }
+
+
+ std::optional airborne_position_with_ref(const std::string& msg_bin, double lat_ref, double lon_ref, Time t, Time t_ref) {
+ auto [YZ, XZ, i] = CPR::get(msg_bin);
+ auto pos = CPR::locale_decode(lat_ref, lon_ref, YZ, XZ, i, 17);
+ if(!pos.has_value()) return std::nullopt;
+ auto [lat, lon] = pos.value();
+ return Position{(double)lat, (double)lon};
+ }
+
+
+ std::string lat_lon_surface_34(double latitude, double longitude, CPR::Frame cpr_format) {
+ auto [YZ, XZ] = CPR::surface_encode(latitude, longitude, cpr_format);
+ return std::bitset<17>(YZ).to_string() + std::bitset<17>(XZ).to_string();
+ }
+
+ std::optional surface_position(const std::string& msg0, const std::string& msg1, Time t0, Time t1, const CPR::Position& base_station_pos) {
+ auto [YZ0, XZ0, i0] = CPR::get(msg0);
+ auto [YZ1, XZ1, i1] = CPR::get(msg1);
+ if (i0 == i1){
+ return std::nullopt;
+ }
+ if(i0 == 1 && i1 == 0){
+ std::swap(YZ0, YZ1);
+ std::swap(XZ0, XZ1);
+ std::swap(t0, t1);
+ std::swap(i0, i1);
+ }
+
+ auto& pos = base_station_pos;
+ auto ref_lat = pos.lat;
+ auto ref_lon = pos.lon;
+ auto poses = CPR::surface_global_decode_ref(YZ0, YZ1, XZ0, XZ1, ref_lat, ref_lon);
+ if(!poses.has_value()) return std::nullopt;
+ auto [pos0, pos1] = poses.value();
+ return (t0 > t1) ? pos0 : pos1;
+ }
+
+
+ std::optional surface_position_with_ref(const std::string& msg_bin, double lat_ref, double lon_ref, Time t, Time t_ref) {
+ auto [YZ, XZ, i] = CPR::get(msg_bin);
+ auto pos = CPR::surface_locale_decode(lat_ref, lon_ref, YZ, XZ, i);
+ if(!pos.has_value()) return std::nullopt;
+ auto [lat, lon] = pos.value();
+ return Position{lat, lon};
+ }
+
+ const D RADIUS = 6371000.0; // 6371 km
+ D haversine(const Position& p1, const Position& p2) {
+ // 将角度转换为弧度
+ D lat1 = p1.lat * M_PI / 180.0;
+ D lon1 = p1.lon * M_PI / 180.0;
+ D lat2 = p2.lat * M_PI / 180.0;
+ D lon2 = p2.lon * M_PI / 180.0;
+ // 经度和纬度差
+ D delta_lat = lat2 - lat1;
+ D delta_lon = lon2 - lon1;
+ // 哈弗辛公式的计算
+ D a = std::sin(delta_lat / 2) * std::sin(delta_lat / 2) +
+ std::cos(lat1) * std::cos(lat2) * std::sin(delta_lon / 2) * std::sin(delta_lon / 2);
+ D c = 2 * std::atan2(std::sqrt(a), std::sqrt(1 - a));
+ // 计算两点之间的距离
+ return RADIUS * c;
+ }
+
+ std::tuple light_time_second_nano(const Position& p1, const Position& p2) {
+ // 计算两点之间的距离(单位:米)
+ D distance = haversine(p1, p2); // 单位:米
+ // 计算光速传播的时间,单位:秒
+ D time_seconds = distance / LIGHT_SPEED;
+ // 计算整数秒部分
+ int seconds = static_cast(time_seconds);
+ // 计算剩余部分转化为纳秒
+ int nanoseconds = static_cast((time_seconds - seconds) * 1e9);
+ return std::make_tuple(seconds, nanoseconds);
+ }
+
+
+ // WGS84 转换成 笛卡尔坐标系
+ constexpr double DEG_TO_RAD_LOCAL = 3.1415926535897932 / 180.0;
+ constexpr double RAD_TO_DEG_LOCAL = 180.0 /3.1415926535897932;
+
+
+ void WGS84_LBH_to_XYZ(double longitude, double latitude, double height, double& X, double& Y, double& Z)
+ {
+ double lon = longitude * DEG_TO_RAD_LOCAL; //经度
+ double lat = latitude * DEG_TO_RAD_LOCAL;
+ double hei = height;
+
+ // variable
+ double a = 6378137.0; //地球赤道半径 ,单位是 m
+ double b = 6356752.31424518; //地球短半轴 ,单位是 m
+ //double E = (a * a - b * b) / (a * a); // E = e^2
+ //std::cout << "E= "<< E << std::endl;
+ //double N = a/(sqrt(1-E*sin(lat)*sin(lat)));
+ double N = a/(sqrt(1-((a * a - b * b) / (a * a)) * sin(lat) * sin(lat)));
+ //std::cout << "N= "<< N << std::endl;
+
+ X =(N + hei ) * cos(lat) * cos(lon);
+ Y =(N + hei ) * cos(lat) * sin(lon);
+ Z =((b * b * N)/ (a * a) + hei) * sin(lat) ;
+ }
+
+ void XYZ_to_WGS84_LBH(double X, double Y, double Z,double& longitude, double& latitude,double& altitude)
+ {
+ double a, b, c, d;
+ // double Longitude;// 经度
+ // double Latitude;// 纬度
+ // double Altitude;// 海拔高度
+ double p, q;
+ double N;
+ a = 6378137.0;
+ b = 6356752.31424518;
+ c = sqrt(((a * a) - (b * b)) / (a * a));
+ d = sqrt(((a * a) - (b * b)) / (b * b));
+ p = sqrt((X * X) + (Y * Y));
+ q = atan2((Z * a), (p * b));
+
+ longitude = atan2(Y, X);
+ N = a / sqrt(1 - ((c * c) * sin(latitude)* sin(latitude)));
+ altitude = (p / cos(latitude)) - N;
+ latitude = atan2((Z + (d * d) * b * pow(sin(q), 3)), (p - (c * c) * a * pow(cos(q), 3)));
+
+ longitude = longitude * RAD_TO_DEG_LOCAL;
+ latitude = latitude * RAD_TO_DEG_LOCAL;
+ }
+} // namespace CPR
+
+}
\ No newline at end of file
diff --git a/SSR/CPR/CPR.h b/SSR/CPR/CPR.h
new file mode 100644
index 0000000..3686dc7
--- /dev/null
+++ b/SSR/CPR/CPR.h
@@ -0,0 +1,140 @@
+#pragma once
+
+#include "../../../Core/Core/Base/JSON.h"
+#include
+#include
+#include