首次提交完整的python工程代码
This commit is contained in:
0
core/__init__.py
Normal file
0
core/__init__.py
Normal file
BIN
core/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
core/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/a2b_forward.cpython-311.pyc
Normal file
BIN
core/__pycache__/a2b_forward.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/b2c_update_rules.cpython-311.pyc
Normal file
BIN
core/__pycache__/b2c_update_rules.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/b_gis_client.cpython-311.pyc
Normal file
BIN
core/__pycache__/b_gis_client.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/bit_packer.cpython-311.pyc
Normal file
BIN
core/__pycache__/bit_packer.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/bit_tools.cpython-311.pyc
Normal file
BIN
core/__pycache__/bit_tools.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/f_to_a_forward.cpython-311.pyc
Normal file
BIN
core/__pycache__/f_to_a_forward.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/forward_engine.cpython-311.pyc
Normal file
BIN
core/__pycache__/forward_engine.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/global_params.cpython-311.pyc
Normal file
BIN
core/__pycache__/global_params.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/link_manager.cpython-311.pyc
Normal file
BIN
core/__pycache__/link_manager.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/single_to_dual.cpython-311.pyc
Normal file
BIN
core/__pycache__/single_to_dual.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/tcp_forward_client.cpython-311.pyc
Normal file
BIN
core/__pycache__/tcp_forward_client.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/tcp_single_to_dual.cpython-311.pyc
Normal file
BIN
core/__pycache__/tcp_single_to_dual.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/udp_c_remote.cpython-311.pyc
Normal file
BIN
core/__pycache__/udp_c_remote.cpython-311.pyc
Normal file
Binary file not shown.
520
core/a2b_forward.py
Normal file
520
core/a2b_forward.py
Normal file
@@ -0,0 +1,520 @@
|
||||
"""
|
||||
2026/4/5
|
||||
TMY
|
||||
A2B转发器,重构:A→B 组帧与发送
|
||||
"""
|
||||
# import socket
|
||||
# from utils.logger import logger
|
||||
# from utils.hex_helper import hex_dump
|
||||
# from processor.telem_config import TELEM_LAYOUT, REVERSE_CALC
|
||||
# from core.bit_packer import BitPacker
|
||||
# from config.settings import SATELLITE_ID
|
||||
|
||||
# # 帧定义
|
||||
# SYNC_HEADER = b'\xEB\x90\xEB\x90'
|
||||
# TAIL = b'\x4C\x3A'
|
||||
|
||||
# # 方向与类型
|
||||
# DIR_TO_SAT = 0x00000001
|
||||
# TYPE_TELEM = 0x00111111
|
||||
|
||||
# class A2BForward:
|
||||
# def __init__(self, local_port, b_ip, b_udp_port):
|
||||
# self.local_port = local_port
|
||||
# self.b_ip = b_ip
|
||||
# self.b_udp_port = b_udp_port
|
||||
|
||||
# self.sock_a = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# self.sock_b = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
# def build_b_frame(self, data_id, values):
|
||||
# # 1) 获取布局与长度
|
||||
# layout = TELEM_LAYOUT[data_id]
|
||||
# data_len_bytes = layout['length']
|
||||
# items = layout['items']
|
||||
|
||||
# # 2) 比特打包
|
||||
# packer = BitPacker(data_len_bytes)
|
||||
# for idx, v in enumerate(values):
|
||||
# if idx >= len(items):
|
||||
# break
|
||||
# item = items[idx]
|
||||
# d_int = REVERSE_CALC(v, item)
|
||||
# packer.set_bits(item['byte'], item['bit'], item['bits'], d_int)
|
||||
|
||||
# data_field = packer.get_bytes()
|
||||
|
||||
# # 3) 组帧
|
||||
# frame = bytearray()
|
||||
# frame += SYNC_HEADER
|
||||
# frame += len(data_field).to_bytes(4, 'big') # 数据长度
|
||||
# frame += DIR_TO_SAT.to_bytes(4, 'big') # 方向
|
||||
# frame += data_id.to_bytes(4, 'big') # 数据代号
|
||||
# frame += TYPE_TELEM.to_bytes(4, 'big') # 类型:遥测
|
||||
# frame += SATELLITE_ID.to_bytes(4, 'big') # 卫星编号
|
||||
# frame += data_field
|
||||
# frame += TAIL
|
||||
|
||||
# return bytes(frame)
|
||||
|
||||
# def loop(self):
|
||||
# self.sock_a.bind(('0.0.0.0', self.local_port))
|
||||
# logger.info(f"A监听UDP: {self.local_port}")
|
||||
|
||||
# while True:
|
||||
# data, _ = self.sock_a.recvfrom(4096)
|
||||
# if len(data) < 24:
|
||||
# continue
|
||||
|
||||
# # 简单解析A帧:取 data_id + 浮点列表
|
||||
# data_id = int.from_bytes(data[8:12], 'big')
|
||||
# float_cnt = (len(data) - 16) // 8
|
||||
# values = []
|
||||
# for i in range(float_cnt):
|
||||
# f = float.from_bytes(data[16 + i*8 : 24 + i*8], 'big')
|
||||
# values.append(f)
|
||||
|
||||
# # 组B帧并发送
|
||||
# b_frame = self.build_b_frame(data_id, values)
|
||||
# self.sock_b.sendto(b_frame, (self.b_ip, self.b_udp_port))
|
||||
# hex_dump(b_frame, f"A→B UDP {self.b_ip}:{self.b_udp_port}")
|
||||
"""
|
||||
2026/4/19
|
||||
Tan Mingyan
|
||||
重写A->B 4中模型的遥测量发送,并保存至全局变量。
|
||||
"""
|
||||
import socket
|
||||
from utils.logger import logger
|
||||
from utils.hex_helper import hex_dump
|
||||
from processor.telem_config import TELEM_LAYOUT, REVERSE_CALC
|
||||
from core.bit_packer import BitPacker
|
||||
#from config.settings import SATELLITE_ID
|
||||
import struct # 👈 新增,用于解析浮点数
|
||||
from core.global_params import get_param, set_param # 顶部导入
|
||||
from core.global_params import TELEM_PARAMS
|
||||
from protocol.a_frame import AFrame
|
||||
# from processor.telem_config import TABLE_MAP, TELEM_COUNT
|
||||
from processor.telm_calc import calc_telem_reverse
|
||||
from protocol.b_frame import build_b_frame
|
||||
#from global_vars import *
|
||||
|
||||
SYNC_HEADER = b'\xEB\x90\xEB\x90'
|
||||
TAIL = b'\x4C\x3A'
|
||||
DIR_TO_SAT = 0x00000001
|
||||
TYPE_TELEM = 0x00111111
|
||||
from config_loader import cfg
|
||||
SATELLITE_ID = cfg.get_int("SATELLITE", "SATELLITE_ID")#2026/4/7 TMY
|
||||
|
||||
class A2BForward:
|
||||
g_vbat_check_cnt =[] #静态变量
|
||||
g_vbat_check_cnt_B =[] #静态变量
|
||||
ck_ab_flag = True #True #测控AB通道有效标志
|
||||
ck_c_flag = True #True #测控C通道有效标志
|
||||
|
||||
def __init__(self, local_port, b_ip, b_udp_port):
|
||||
self.local_port = local_port
|
||||
self.b_ip = b_ip
|
||||
self.b_udp_port = b_udp_port
|
||||
|
||||
self.sock_a = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.sock_b = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
self.g_vbat_check_cnt = [0,0,0,0] #静态变量
|
||||
self.g_vbat_check_cnt_B = [0,0,0,0] #静态变量
|
||||
self.gufangA_power = 0
|
||||
self.gufangB_power = 0
|
||||
self.kuopinA_5V = 0
|
||||
self.kuopinB_5V = 0
|
||||
#上一次接收到的值
|
||||
self.gufangA_power_former = 0
|
||||
|
||||
self.gufangB_power_former = 0
|
||||
self.kuopinA_5V_former = 0
|
||||
self.kuopinB_5V_former = 0
|
||||
self.yitiji_5v_former = 0
|
||||
self.yitiji_5v = 0
|
||||
self.ck_ab_flag = True #测控AB通道有效标志
|
||||
self.ck_a_flag = True #测控A通道有效标志
|
||||
self.ck_b_flag = True #测控B通道有效标志
|
||||
|
||||
self.ck_c_flag = True #测控C通道有效标志
|
||||
|
||||
self.receive_A_frame_count = 0
|
||||
self.A_battery_v_direct = 0
|
||||
self.B_battery_v_direct = 0
|
||||
|
||||
def build_b_frame(self, data_id,satelllite_id, values):
|
||||
#print(data_id)
|
||||
layout = TELEM_LAYOUT[data_id]
|
||||
data_len = layout['length']
|
||||
items = layout['items']
|
||||
|
||||
packer = BitPacker(data_len)
|
||||
for idx, y in enumerate(values):
|
||||
if idx >= len(items):
|
||||
break
|
||||
it = items[idx]
|
||||
d = REVERSE_CALC(y, it)##反推的值,然后存入全局变量?
|
||||
if self.receive_A_frame_count % 10 == 0:#每100帧才打印1次A软件输入参数,避免日志过大
|
||||
#print(f"输入y={y}, 配置it={it}, 反推d={d}")
|
||||
logger.info((f"输入y={y}, 配置it={it}, 反推d={d}"))
|
||||
self.receive_A_frame_count = 0
|
||||
|
||||
|
||||
# ====================== 【核心:存入全局变量】 ======================2026/4/18
|
||||
if 'param_num' in it:
|
||||
set_param(it['param_num'], d) # 按代号存入全局
|
||||
|
||||
#存入一些原值为全局变量 2026/4/30
|
||||
if it['param_num'] == 'M001CV024':
|
||||
self.gufangA_power = y
|
||||
if it['param_num'] == 'M001CV029':
|
||||
self.gufangB_power = y
|
||||
if it['param_num'] == 'M001CV002':
|
||||
self.kuopinA_5V = y
|
||||
if it['param_num'] == 'M001CV013':
|
||||
self.kuopinB_5V = y
|
||||
if it['param_num'] == 'M085CV004':
|
||||
self.yitiji_5v = y
|
||||
|
||||
if it['param_num'] == 'M010YV012':
|
||||
self.A_battery_v_direct = y
|
||||
if it['param_num'] == 'M010YV014':
|
||||
self.B_battery_v_direct = y
|
||||
|
||||
#写入A->B帧
|
||||
packer.set_bits(it['byte'], it['bit'], it['bits'], d)
|
||||
|
||||
data_field = packer.get_bytes()
|
||||
|
||||
# 组帧
|
||||
frame = bytearray()
|
||||
frame += SYNC_HEADER
|
||||
frame += len(data_field).to_bytes(4, 'big')
|
||||
frame += DIR_TO_SAT.to_bytes(4, 'big')
|
||||
frame += data_id.to_bytes(4, 'big')
|
||||
frame += TYPE_TELEM.to_bytes(4, 'big')
|
||||
#frame += SATELLITE_ID.to_bytes(4, 'big')
|
||||
frame += satelllite_id.to_bytes(4, 'big')#2026/4/7 TMY
|
||||
frame += data_field
|
||||
frame += TAIL
|
||||
|
||||
self.receive_A_frame_count += 1
|
||||
return bytes(frame)
|
||||
|
||||
|
||||
|
||||
def check_battery_safe_mode(self):#判断整星安全模式
|
||||
|
||||
# 蓄电池组A
|
||||
# ====================== 1. 计算三路电池电压 ======================
|
||||
Vbat1 = get_param('M002YV020',0) *0.01837765 - 0.00943934 # 整组电池1,A组蓄电池组电压
|
||||
#Vbat2 = get_param('M010YV012',0) * 16.56008 -0.01009 # 整组电池2,M010YV012A蓄电池组电压-直
|
||||
#Vbat2 = self.A_battery_v_direct #2026/5/9 暂时来源为0,所以屏蔽
|
||||
Vbat2 = Vbat1 #2026/5/9
|
||||
Vbat3 = (get_param('M004YV002',0) + get_param('M004YV004',0) +
|
||||
get_param('M004YV006',0) + get_param('M004YV008',0) +
|
||||
get_param('M004YV010',0) + get_param('M004YV012',0) +
|
||||
get_param('M004YV014',0) + get_param('M004YV016',0) + get_param('M004YV018',0))* 0.00244140625 # 单体总和
|
||||
|
||||
Vth1 = 30 #
|
||||
Vth2 = 28.998 # g_M050YV002,29.998,2026/5/12 不改为29.9.
|
||||
Vth3 = 24.999 # g_M050YV003
|
||||
Vth4 = 3.2983398 #M050YV004 A单体过放电VCOD1阈值-软
|
||||
|
||||
# # ====================== 2. 单次判断:是否低于阈值 ======================
|
||||
# fail1 = 1 if (Vbat1 < Vth1) else 0
|
||||
# fail2 = 1 if (Vbat2 < Vth2) else 0
|
||||
# fail3 = 1 if (Vbat3 < Vth3) else 0
|
||||
fail11 = 1 if (Vbat1 < Vth1) else 0
|
||||
fail21 = 1 if (Vbat2 < Vth1) else 0
|
||||
fail31 = 1 if (Vbat3 < Vth1) else 0
|
||||
fail12 = 1 if (Vbat1 < Vth2) else 0
|
||||
fail22 = 1 if (Vbat2 < Vth2) else 0
|
||||
fail32 = 1 if (Vbat3 < Vth2) else 0
|
||||
fail13 = 1 if (Vbat1 < Vth3) else 0
|
||||
fail23 = 1 if (Vbat2 < Vth3) else 0
|
||||
fail33 = 1 if (Vbat3 < Vth3) else 0
|
||||
fail4 = 1 if(Vbat3 < Vth4 * 9) else 0
|
||||
# # ====================== 3. 连续3次判断 ======================
|
||||
# total_fail = fail1 + fail2 + fail3
|
||||
|
||||
# if total_fail >= 2:
|
||||
# g_vbat_check_cnt += 1
|
||||
# g_vbat_fail_flag = [fail1, fail2, fail3]
|
||||
# else:
|
||||
# g_vbat_check_cnt = 0
|
||||
# g_vbat_fail_flag = [0, 0, 0]
|
||||
total_fail1 = fail11 + fail21 + fail31#低于VBOD1的数量
|
||||
total_fail2 = fail12 + fail22 + fail32#低于VBOD2的数量
|
||||
total_fail3 = fail13 + fail23 + fail33#低于VBOD3的数量
|
||||
|
||||
if total_fail1 >= 2:
|
||||
self.g_vbat_check_cnt[0] += 1
|
||||
else:
|
||||
self.g_vbat_check_cnt[0] = 0
|
||||
if total_fail2 >= 2:
|
||||
self.g_vbat_check_cnt[1] += 1
|
||||
else:
|
||||
self.g_vbat_check_cnt[1] = 0
|
||||
if total_fail3 >= 2:
|
||||
self.g_vbat_check_cnt[2] += 1
|
||||
else:
|
||||
self.g_vbat_check_cnt[2] = 0
|
||||
if fail4 >0:
|
||||
self.g_vbat_check_cnt[3] += 1
|
||||
else:
|
||||
self.g_vbat_check_cnt[3] = 0
|
||||
|
||||
# 超限3次锁定报警
|
||||
# if g_vbat_check_cnt >= 3:
|
||||
# g_M050YS055 = g_vbat_fail_flag[0]
|
||||
# g_M050YS056 = g_vbat_fail_flag[1]
|
||||
# g_M050YS057 = g_vbat_fail_flag[2]
|
||||
# else:
|
||||
# g_M050YS055 = 0
|
||||
# g_M050YS056 = 0
|
||||
# g_M050YS057 = 0
|
||||
## 分别产生过放电报警信号VBOD1~VBOD3(M050YS055改为1,M050YS056改为1,M050YS057改为1),否则都发别更改为0
|
||||
if self.g_vbat_check_cnt[0]>=3 :
|
||||
g_M050YS055 = 1
|
||||
set_param('M050YS055', 1) # 按代号存入全局
|
||||
else:
|
||||
g_M050YS055 = 0
|
||||
set_param('M050YS055', 0) # 按代号存入全局
|
||||
if self.g_vbat_check_cnt[1]>=3 :
|
||||
g_M050YS056 = 1
|
||||
set_param('M050YS056', 1) # 按代号存入全局
|
||||
else:
|
||||
g_M050YS056 = 1
|
||||
set_param('M050YS056', 0) # 按代号存入全局
|
||||
if self.g_vbat_check_cnt[2]>=3 :
|
||||
g_M050YS057 = 1
|
||||
set_param('M050YS057', 1) # 按代号存入全局
|
||||
else:
|
||||
g_M050YS057 = 1
|
||||
set_param('M050YS057', 0) # 按代号存入全局
|
||||
|
||||
if self.g_vbat_check_cnt[3]>=3 :
|
||||
g_M050YS058 = 1
|
||||
set_param('M050YS058', 1) # 按代号存入全局
|
||||
else:
|
||||
g_M050YS058 = 1
|
||||
set_param('M050YS058', 0) # 按代号存入全局
|
||||
|
||||
# ====================== 4. 整星安全模式触发条件 ======================
|
||||
## 当蓄电池组电压M002YV020小于VBOD2(M050YV002)(初始阈值为29V)时,产生“整组过放电2”报警信号,即把M050YS056改为1,此时卫星进入整星安全模式,修改M050YG073供电模式为1;否则修改为0
|
||||
if Vbat2 < Vth2: # 小于阈值2(默认29V)
|
||||
g_M050YS056 = 1
|
||||
g_M050YG073 = 1 # 进入安全模式
|
||||
set_param('M050YS056', 1) # 按代号存入全局
|
||||
set_param('M050YG073', 1) # 按代号存入全局
|
||||
|
||||
set_param('M014ZG027', 9) # 按代号存入全局,M014ZG027 整星进入安全模式原因
|
||||
else:
|
||||
g_M050YS056 = 0
|
||||
g_M050YG073 = 0 # 退出安全模式
|
||||
set_param('M050YS056', 0) # 按代号存入全局
|
||||
set_param('M050YG073', 0) # 按代号存入全局
|
||||
set_param('M014ZG027', 0) # 按代号存入全局,M014ZG027 整星进入安全模式原因
|
||||
|
||||
|
||||
##蓄电池组B的逻辑和A完全一样
|
||||
# ====================== 1. 计算三路电池电压 ======================
|
||||
Vbat1_B = get_param('M002YV054',0) * 0.01856155 -0.01615284 # 整组电池1
|
||||
#Vbat2_B = get_param('M010YV014',0) * 16.473805 - 0.009011 # 整组电池2
|
||||
#Vbat2_B =self.B_battery_v_direct # 整组电池2
|
||||
Vbat2_B = Vbat1_B
|
||||
Vbat3_B = (get_param('M004YV022',0) + get_param('M004YV024',0) +
|
||||
get_param('M004YV026',0) + get_param('M004YV028',0) +
|
||||
get_param('M004YV030',0) + get_param('M004YV032',0) +
|
||||
get_param('M004YV034',0) + get_param('M004YV036',0) + get_param('M004YV038',0))* 0.00244140625 # 单体总和
|
||||
|
||||
Vth1_B = 30 # M050YV021
|
||||
Vth2_B = 29 # M050YV022
|
||||
Vth3_B = 25 # M050YV023
|
||||
Vth4_B= 3.2983398 #M050YV024 B单体过放电VCOD1阈值-软
|
||||
|
||||
# # ====================== 2. 单次判断:是否低于阈值 ======================
|
||||
# fail1 = 1 if (Vbat1 < Vth1) else 0
|
||||
# fail2 = 1 if (Vbat2 < Vth2) else 0
|
||||
# fail3 = 1 if (Vbat3 < Vth3) else 0
|
||||
fail11_B = 1 if (Vbat1_B < Vth1_B) else 0
|
||||
fail21_B = 1 if (Vbat2_B < Vth1_B) else 0
|
||||
fail31_B = 1 if (Vbat3_B < Vth1_B) else 0
|
||||
fail12_B = 1 if (Vbat1_B < Vth2_B) else 0
|
||||
fail22_B = 1 if (Vbat2_B < Vth2_B) else 0
|
||||
fail32_B = 1 if (Vbat3_B < Vth2_B) else 0
|
||||
fail13_B = 1 if (Vbat1_B < Vth3_B) else 0
|
||||
fail23_B = 1 if (Vbat2_B < Vth3_B) else 0
|
||||
fail33_B = 1 if (Vbat3_B < Vth3_B) else 0
|
||||
fail4_B = 1 if(Vbat3_B < Vth4_B * 9) else 0
|
||||
|
||||
# # ====================== 3. 连续3次判断 ======================
|
||||
# total_fail = fail1 + fail2 + fail3
|
||||
|
||||
# if total_fail >= 2:
|
||||
# g_vbat_check_cnt += 1
|
||||
# g_vbat_fail_flag = [fail1, fail2, fail3]
|
||||
# else:
|
||||
# g_vbat_check_cnt = 0
|
||||
# g_vbat_fail_flag = [0, 0, 0]
|
||||
total_fail1_B = fail11_B + fail21_B + fail31_B#低于VBOD1的数量
|
||||
total_fail2_B = fail12_B + fail22_B + fail32_B#低于VBOD2的数量
|
||||
total_fail3_B = fail13_B + fail23_B + fail33_B#低于VBOD3的数量
|
||||
|
||||
if total_fail1_B >= 2:
|
||||
self.g_vbat_check_cnt_B[0] += 1
|
||||
else:
|
||||
self.g_vbat_check_cnt_B[0]=0
|
||||
if total_fail2_B >= 2:
|
||||
self.g_vbat_check_cnt_B[1] += 1
|
||||
else:
|
||||
self.g_vbat_check_cnt_B[1]=0
|
||||
if total_fail3_B >= 2:
|
||||
self.g_vbat_check_cnt_B[2] += 1
|
||||
else:
|
||||
self.g_vbat_check_cnt_B[2]=0
|
||||
if fail4_B >= 1:
|
||||
self.g_vbat_check_cnt_B[3] += 1
|
||||
else:
|
||||
self.g_vbat_check_cnt_B[3]=0
|
||||
|
||||
# 超限3次锁定报警
|
||||
# if g_vbat_check_cnt >= 3:
|
||||
# g_M050YS055 = g_vbat_fail_flag[0]
|
||||
# g_M050YS056 = g_vbat_fail_flag[1]
|
||||
# g_M050YS057 = g_vbat_fail_flag[2]
|
||||
# else:
|
||||
# g_M050YS055 = 0
|
||||
# g_M050YS056 = 0
|
||||
# g_M050YS057 = 0
|
||||
## 分别产生过放电报警信号VBOD1~VBOD3(M050YS055改为1,M050YS056改为1,M050YS057改为1),否则都发别更改为0
|
||||
if self.g_vbat_check_cnt_B[0]>=3 :
|
||||
g_M050YS067 = 1
|
||||
set_param('M050YS067', 1) # 按代号存入全局
|
||||
else:
|
||||
g_M050YS067 = 0
|
||||
set_param('M050YS067', 0) # 按代号存入全局
|
||||
if self.g_vbat_check_cnt_B[1]>=3 :
|
||||
g_M050YS068 = 1
|
||||
set_param('M050YS068', 1) # 按代号存入全局
|
||||
else:
|
||||
g_M050YS068 = 1
|
||||
set_param('M050YS068', 0) # 按代号存入全局
|
||||
if self.g_vbat_check_cnt_B[2]>=3 :
|
||||
g_M050YS069 = 1
|
||||
set_param('M050YS069', 1) # 按代号存入全局
|
||||
else:
|
||||
g_M050YS069 = 1
|
||||
set_param('M050YS069', 0) # 按代号存入全局
|
||||
if self.g_vbat_check_cnt_B[3]>=3 :
|
||||
g_M050YS070 = 1
|
||||
set_param('M050YS070', 1) # 按代号存入全局
|
||||
else:
|
||||
g_M050YS070 = 1
|
||||
set_param('M050YS070', 0) # 按代号存入全局
|
||||
|
||||
|
||||
# ====================== 4. 整星安全模式触发条件 ======================
|
||||
## 当蓄电池组电压M002YV020小于VBOD2(M050YV002)(初始阈值为29V)时,产生“整组过放电2”报警信号,即把M050YS056改为1,此时卫星进入整星安全模式,修改M050YG073供电模式为1;否则修改为0
|
||||
if Vbat2_B < Vth2_B: # 小于阈值2(默认29V)
|
||||
g_M050YS068 = 1
|
||||
g_M050YG073 = 1 # 进入安全模式
|
||||
set_param('M050YS068', 1) # 按代号存入全局
|
||||
set_param('M050YG073', 1) # 按代号存入全局
|
||||
else:
|
||||
g_M050YS068 = 0
|
||||
#g_M050YG073 = 0 # 退出安全模式
|
||||
set_param('M050YS068', 0) # 按代号存入全局
|
||||
#set_param('M050YG073', 0) # 按代号存入全局
|
||||
|
||||
def change_ck_mode(self):
|
||||
# gufangA_power = get_param('M001CV024',0) *1
|
||||
# kuopinA_5V = get_param('M001CV002',0)*1
|
||||
# gufangB_power = get_param('M001CV029',0) *1
|
||||
# kuopinB_5V = get_param('M001CV013',0)*1
|
||||
print(f"self.gufangA_power_former={self.gufangA_power_former},self.gufangA_power={self.gufangA_power}")
|
||||
#测控ab通道正常发遥测,监测判断:(M001CV024固放A功率从10变为0或M001CV002扩频A+5V从5变为0)且(M001CV029固放B功率从10变为0或M001CV013扩频B+5V从5变为0),则停掉测控AB遥测转发,地面向星务发送切C通道遥测指令后,星务模型播发C通道遥测,转发到地面解析,
|
||||
if ((self.gufangA_power_former > 9 and self.gufangA_power < 0.1)or(self.kuopinA_5V_former>4.9 and self.kuopinA_5V<0.1)) and ((self.gufangB_power_former > 9 and self.gufangB_power < 0.1)or(self.kuopinB_5V_former>4.9 and self.kuopinB_5V<0.1)) :
|
||||
self.ck_ab_flag = False ## 暂时and改成or!!!,已经改回来。这样的判断导致AB不同时失效时无法触发异常处理。
|
||||
A2BForward.ck_ab_flag = False
|
||||
|
||||
if((self.gufangA_power_former > 9 and self.gufangA_power < 0.1)or(self.kuopinA_5V_former>4.9 and self.kuopinA_5V<0.1)):
|
||||
self.ck_a_flag = False #测控A异常标志
|
||||
if((self.gufangB_power_former > 9 and self.gufangB_power < 0.1)or(self.kuopinB_5V_former>4.9 and self.kuopinB_5V<0.1)):
|
||||
self.ck_b_flag = False #测控B异常标志
|
||||
if(self.ck_a_flag == False and self.ck_b_flag == False):
|
||||
self.ck_ab_flag = False ## 测控A,B异常标志
|
||||
A2BForward.ck_ab_flag = False
|
||||
|
||||
self.gufangA_power_former = self.gufangA_power #上一次接收到的值
|
||||
self.gufangB_power_former = self.gufangB_power
|
||||
self.kuopinA_5V_former = self.kuopinA_5V
|
||||
self.kuopinB_5V_former = self.kuopinB_5V
|
||||
|
||||
#监测判断M085CV004一体机+5V电源-直,从5变为0,则停掉C通道遥测转发
|
||||
if((self.yitiji_5v_former>4.8)and(self.yitiji_5v)<0.1):
|
||||
self.ck_c_flag = False
|
||||
A2BForward.ck_c_flag = False
|
||||
if(self.yitiji_5v>4.8):
|
||||
self.ck_c_flag = True
|
||||
A2BForward.ck_c_flag = True
|
||||
self.yitiji_5v_former = self.yitiji_5v
|
||||
|
||||
def loop(self):
|
||||
self.sock_a.bind(('0.0.0.0', self.local_port))
|
||||
logger.info(f"监听A UDP: {self.local_port}")
|
||||
|
||||
while True:
|
||||
data, _ = self.sock_a.recvfrom(8192)
|
||||
if len(data) < 24:
|
||||
continue
|
||||
s = data.hex(" ").upper()
|
||||
logger.info(f"A同元的帧: {s}")
|
||||
|
||||
#data_id = int.from_bytes(data[8:12], 'big')#错误
|
||||
data_id = int.from_bytes(data[12:16], 'big')
|
||||
satelllite_id = int.from_bytes(data[20:24], 'big')
|
||||
#float_cnt = (len(data) - 16) // 8
|
||||
float_cnt = int.from_bytes(data[4:8], 'big')//8 #最新协议规定是double数据的数量,不是字节数 2026/4/19 TMY 同元做法就是字节数 2026/4/20
|
||||
print(f"有 {float_cnt} 个8B浮点数")
|
||||
values = []
|
||||
for i in range(float_cnt):
|
||||
# f = float.from_bytes(data[16+i*8 : 24+i*8], 'big')
|
||||
# values.append(f)
|
||||
start = 24 + i * 8 #start = 16 + i * 8
|
||||
end = start + 8
|
||||
if end > len(data):#判断读取是否越界
|
||||
break
|
||||
# 👈 修复点:使用 struct 解析 8 字节大端 double
|
||||
f = struct.unpack('>d', data[start:end])[0]
|
||||
values.append(f)
|
||||
|
||||
# # 逆运算反推原始值
|
||||
# frame = AFrame(data)
|
||||
# data_id = frame.data_id
|
||||
# if data_id not in TABLE_MAP:
|
||||
# continue
|
||||
# processed = []
|
||||
# table = TABLE_MAP[data_id]
|
||||
# for idx, v in enumerate(values):
|
||||
# if idx >= len(table):
|
||||
# processed.append(v)
|
||||
# continue
|
||||
# name, method, param = table[idx]
|
||||
# pv = calc_telem_reverse(v, method, param)
|
||||
# print(f"[{name}] 输入Y: {v:.6f},反推D: {pv:.2f}")
|
||||
# processed.append(pv)
|
||||
#b_frame = build_b_frame(data_id, processed)#2026/4/20 TMY
|
||||
b_frame = self.build_b_frame(data_id,satelllite_id, values)
|
||||
|
||||
# self.sock_b.sendto(b_frame, (self.b_ip, self.b_udp_port)) #B软件暂时无法解析这个数据,先不发 2026/5/7
|
||||
# hex_dump(b_frame, f"A→B UDP {self.b_ip}:{self.b_udp_port}")
|
||||
|
||||
|
||||
##实现更新安全模式的方法
|
||||
self.check_battery_safe_mode()
|
||||
## AB测控帧头检测
|
||||
self.change_ck_mode()
|
||||
|
||||
134
core/a2b_forward_old.py
Normal file
134
core/a2b_forward_old.py
Normal file
@@ -0,0 +1,134 @@
|
||||
|
||||
"""
|
||||
##A→B 转发主逻辑(UDP 监听 5000 → TCP 发 B)2026/3/29 2026/4/3停用
|
||||
import socket
|
||||
import threading
|
||||
from utils.logger import logger
|
||||
from utils.hex_helper import hex_dump
|
||||
from protocol.a_frame import AFrame
|
||||
from protocol.b_frame import build_b_frame
|
||||
from processor.telem_config import TABLE_MAP, TELEM_COUNT
|
||||
from processor.telm_calc import calc_telem, calc_telem_reverse
|
||||
|
||||
class A2BForward:
|
||||
def __init__(self, local_port, tcp_ip, tcp_port):
|
||||
self.local_port = local_port
|
||||
self.tcp_ip = tcp_ip
|
||||
self.tcp_port = tcp_port
|
||||
self.sock_tcp = None
|
||||
|
||||
def connect_b(self):
|
||||
while True:
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((self.tcp_ip, self.tcp_port))
|
||||
self.sock_tcp = s
|
||||
logger.info("✅ 已连接B软件")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error("连接B失败,重连中")
|
||||
threading.Event().wait(2)
|
||||
|
||||
def loop(self):
|
||||
sock_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock_udp.bind(("0.0.0.0", self.local_port))
|
||||
logger.info(f"✅ 监听A软件 UDP:{self.local_port}")
|
||||
|
||||
self.connect_b()
|
||||
|
||||
while True:
|
||||
data, addr = sock_udp.recvfrom(4096)
|
||||
frame = AFrame(data)
|
||||
if not frame.valid:
|
||||
continue
|
||||
|
||||
data_id = frame.data_id
|
||||
if data_id not in TABLE_MAP:
|
||||
continue
|
||||
|
||||
expect_cnt = TELEM_COUNT[data_id]
|
||||
values = frame.values[:expect_cnt]
|
||||
table = TABLE_MAP[data_id]
|
||||
|
||||
# 计算所有遥测
|
||||
#ref_cache = {}
|
||||
processed = []
|
||||
for idx, v in enumerate(values):
|
||||
if idx >= len(table):
|
||||
processed.append(v)
|
||||
continue
|
||||
name, method, param = table[idx]
|
||||
#pv = calc_telem(v, method, param, ref_cache)
|
||||
# 处理前
|
||||
#print(f"[{name}] 输入Y: {v:.6f}")
|
||||
pv = calc_telem_reverse(v, method, param)#改为逆运算
|
||||
print(f"[{name}] 输入Y: {v:.6f},反推D: {pv:.2f}")
|
||||
processed.append(pv)
|
||||
|
||||
# 组B帧并发送
|
||||
b_frame = build_b_frame(data_id, processed)
|
||||
try:
|
||||
self.sock_tcp.send(b_frame)
|
||||
except:
|
||||
self.connect_b()
|
||||
self.sock_tcp.send(b_frame)
|
||||
|
||||
hex_dump(b_frame, "已发往B软件")
|
||||
"""
|
||||
# 修改 A→B 发送逻辑(核心) 2026/4/3
|
||||
import socket
|
||||
import threading
|
||||
from utils.logger import logger
|
||||
from utils.hex_helper import hex_dump
|
||||
from protocol.a_frame import AFrame
|
||||
from protocol.b_frame import build_b_frame
|
||||
from processor.telem_config import TABLE_MAP, TELEM_COUNT
|
||||
from processor.telm_calc import calc_telem_reverse
|
||||
|
||||
class A2BForward:
|
||||
def __init__(self, local_port, b_ip, b_udp_port):
|
||||
self.local_port = local_port # 5000
|
||||
self.b_ip = b_ip # 10.20.97.166
|
||||
self.b_udp_port = b_udp_port # B 新UDP端口
|
||||
|
||||
# 监听 A 的 UDP
|
||||
self.sock_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# 发给 B 的 UDP(新链路)
|
||||
self.sock_to_b = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
def loop(self):
|
||||
self.sock_udp.bind(("0.0.0.0", self.local_port))
|
||||
logger.info(f"✅ 监听 A UDP: {self.local_port}")
|
||||
|
||||
while True:
|
||||
data, addr = self.sock_udp.recvfrom(4096)
|
||||
frame = AFrame(data)
|
||||
if not frame.valid:
|
||||
continue
|
||||
|
||||
data_id = frame.data_id
|
||||
if data_id not in TABLE_MAP:
|
||||
continue
|
||||
|
||||
expect_cnt = TELEM_COUNT[data_id]
|
||||
values = frame.values[:expect_cnt]
|
||||
table = TABLE_MAP[data_id]
|
||||
|
||||
# 逆运算反推原始值
|
||||
processed = []
|
||||
for idx, v in enumerate(values):
|
||||
if idx >= len(table):
|
||||
processed.append(v)
|
||||
continue
|
||||
name, method, param = table[idx]
|
||||
pv = calc_telem_reverse(v, method, param)
|
||||
print(f"[{name}] 输入Y: {v:.6f},反推D: {pv:.2f}")
|
||||
processed.append(pv)
|
||||
|
||||
# 组帧
|
||||
b_frame = build_b_frame(data_id, processed)
|
||||
|
||||
# ===================== 发给 B:UDP 发送 =====================
|
||||
self.sock_to_b.sendto(b_frame, (self.b_ip, self.b_udp_port))
|
||||
|
||||
hex_dump(b_frame, f"✅ A→B 已通过 UDP 发往 B: {self.b_ip}:{self.b_udp_port}")
|
||||
868
core/b2c_update_rules.py
Normal file
868
core/b2c_update_rules.py
Normal file
@@ -0,0 +1,868 @@
|
||||
"""
|
||||
2026/4/18
|
||||
Tan Mingyan
|
||||
B软件数字卫星遥测帧-> C软件遥测数据更新规则
|
||||
"""
|
||||
# 格式:
|
||||
# 包代号: [
|
||||
# (参数代号, 起始字节, 起始比特, 比特数),
|
||||
# ...
|
||||
# ]
|
||||
"""
|
||||
B2C_UPDATE_RULES = {
|
||||
1: [
|
||||
("M001CT001", 0, 0, 8),
|
||||
("M001CV002", 1, 0, 8),
|
||||
("M001CV003", 2, 0, 8),
|
||||
("M001CV004", 3, 0, 8),
|
||||
("M001CS005", 4, 0, 1),
|
||||
("M001CS006", 5, 0, 1),
|
||||
("M001CS007", 6, 0, 1),
|
||||
("M001CS008", 7, 0, 1),
|
||||
("M001CS009", 8, 0, 1),
|
||||
("M001CS010", 9, 0, 1),
|
||||
("M001CS011", 10, 0, 1),
|
||||
("M001CT012", 11, 0, 8),
|
||||
("M001CV013", 12, 0, 8),
|
||||
("M001CV014", 13, 0, 8),
|
||||
("M001CV015", 14, 0, 8),
|
||||
("M001CS016", 15, 0, 1),
|
||||
("M001CS017", 16, 0, 1),
|
||||
("M001CS018", 17, 0, 1),
|
||||
("M001CS019", 18, 0, 1),
|
||||
("M001CS020", 19, 0, 1),
|
||||
("M001CS021", 20, 0, 1),
|
||||
("M001CS022", 21, 0, 1),
|
||||
("M001CV023", 22, 0, 8),
|
||||
("M001CV024", 23, 0, 8),
|
||||
("M001CT025", 24, 0, 8),
|
||||
("M001CS026", 25, 0, 1),
|
||||
("M001CI027", 26, 0, 8),
|
||||
("M001CV028", 27, 0, 8),
|
||||
("M001CV029", 28, 0, 8),
|
||||
("M001CT030", 29, 0, 8),
|
||||
("M001CS031", 30, 0, 1),
|
||||
("M001CI032", 31, 0, 8),
|
||||
("M001CT033", 32, 0, 8),
|
||||
("M001CS034", 33, 0, 1),
|
||||
("M001CS035", 34, 0, 1),
|
||||
],
|
||||
2: [
|
||||
("M002YI002", 0, 4, 12),
|
||||
("M002YI004", 2, 4, 12),
|
||||
("M002YI006", 4, 4, 12),
|
||||
("M002YI008", 6, 4, 12),
|
||||
("M002YI010", 8, 4, 12),
|
||||
("M002YI012", 10, 4, 12),
|
||||
("M002YI014", 12, 4, 12),
|
||||
("M002YI016", 14, 4, 12),
|
||||
("M002YV018", 16, 4, 12),
|
||||
("M002YV020", 18, 4, 12),
|
||||
("M002YV022", 20, 4, 12),
|
||||
("M002YV024", 22, 4, 12),
|
||||
("M002YS025", 24, 0, 8),
|
||||
("M002YS026", 25, 0, 8),
|
||||
("M002YS027", 26, 0, 8),
|
||||
("M002YS028", 27, 0, 8),
|
||||
("M002YS029", 28, 0, 8),
|
||||
("M002YS030", 29, 0, 8),
|
||||
("M002YS031", 30, 0, 8),
|
||||
("M002YS032", 31, 0, 8),
|
||||
("M002YS033", 32, 0, 8),
|
||||
("M002YS034", 33, 0, 8),
|
||||
("M002YS035", 34, 0, 8),
|
||||
("M002YS036", 35, 0, 8),
|
||||
("M002YI040", 38, 4, 12),
|
||||
("M002YI042", 40, 4, 12),
|
||||
("M002YI044", 42, 4, 12),
|
||||
("M002YI046", 44, 4, 12),
|
||||
("M002YI048", 46, 4, 12),
|
||||
("M002YI050", 48, 4, 12),
|
||||
("M002YI052", 50, 4, 12),
|
||||
("M002YV054", 52, 4, 12),
|
||||
("M002YV056", 54, 4, 12),
|
||||
],
|
||||
3: [
|
||||
("M003YI002", 0, 4, 12),
|
||||
("M003YI004", 2, 4, 12),
|
||||
("M003YG027", 24, 0, 4),
|
||||
("M003YG028", 24, 4, 4),
|
||||
("M003YG029", 25, 0, 4),
|
||||
("M003YG030", 25, 4, 4),
|
||||
("M003YI034", 28, 4, 12),
|
||||
("M003YI036", 30, 4, 12),
|
||||
],
|
||||
4: [
|
||||
("M004YV002", 0, 4, 12),
|
||||
("M004YV004", 2, 4, 12),
|
||||
("M004YV006", 4, 4, 12),
|
||||
("M004YV008", 6, 4, 12),
|
||||
("M004YV010", 8, 4, 12),
|
||||
("M004YV012", 10, 4, 12),
|
||||
("M004YV014", 12, 4, 12),
|
||||
("M004YV016", 14, 4, 12),
|
||||
("M004YV018", 16, 4, 12),
|
||||
("M004YV022", 20, 4, 12),
|
||||
("M004YV024", 22, 4, 12),
|
||||
("M004YV026", 24, 4, 12),
|
||||
("M004YV028", 26, 4, 12),
|
||||
("M004YV030", 28, 4, 12),
|
||||
("M004YV032", 30, 4, 12),
|
||||
("M004YV034", 32, 4, 12),
|
||||
("M004YV036", 34, 4, 12),
|
||||
("M004YV038", 36, 4, 12),
|
||||
],
|
||||
19: [
|
||||
("M019XV005", 8, 0, 16),
|
||||
],
|
||||
18: [
|
||||
("M018XV017", 32, 0, 16),
|
||||
("M018XV019", 36, 0, 16),
|
||||
],
|
||||
57: [
|
||||
("M057JS005", 3, 1, 1),
|
||||
("M057JS006", 3, 2, 1),
|
||||
("M057JS007", 3, 3, 1),
|
||||
("M057JS008", 3, 4, 1),
|
||||
("M057JS009", 3, 5, 1),
|
||||
("M057JS010", 3, 6, 1),
|
||||
("M057JS012", 4, 1, 1),
|
||||
("M057JS013", 4, 2, 1),
|
||||
("M057JS014", 4, 3, 3),
|
||||
("M057JS015", 4, 6, 3),
|
||||
("M057JS017", 5, 2, 1),
|
||||
("M057JS018", 5, 3, 1),
|
||||
("M057JG023", 10, 0, 16),
|
||||
("M057JG024", 12, 0, 16),
|
||||
#("M057JG039", 42, 0, 32),
|
||||
("M057JG040", 46, 0, 32),
|
||||
],
|
||||
79: [
|
||||
("M079CG032", 16, 2, 2),
|
||||
("M079CS033", 16, 4, 1),
|
||||
("M079CS034", 16, 5, 1),
|
||||
],
|
||||
85: [
|
||||
("M085TV003", 3, 0, 16),
|
||||
("M085CV004", 5, 0, 16),
|
||||
],
|
||||
87: [
|
||||
("M087CS063", 47, 3, 1),
|
||||
("M087CS064", 47, 4, 1),
|
||||
("M087CS065", 47, 5, 1),
|
||||
("M087CS066", 47, 6, 1),
|
||||
("M087CS067", 47, 7, 1),
|
||||
("M087CS068", 48, 0, 1),
|
||||
("M087CS069", 48, 1, 1),
|
||||
("M087CS078", 49, 2, 1),
|
||||
("M087CS079", 49, 3, 1),
|
||||
],
|
||||
}
|
||||
"""
|
||||
|
||||
"""
|
||||
# 最新B->C遥测替换规则 2026-04-19
|
||||
# 已完成所有偏移量计算、多包号拆分、统一字节偏移
|
||||
B2C_UPDATE_RULES = {
|
||||
# 包1
|
||||
1: [
|
||||
("M001CT001", 132, 0, 8),
|
||||
("M001CV002", 133, 0, 8),
|
||||
("M001CV003", 134, 0, 8),
|
||||
("M001CV004", 135, 0, 8),
|
||||
("M001CS005", 136, 0, 1),
|
||||
("M001CS006", 137, 0, 1),
|
||||
("M001CS007", 138, 0, 1),
|
||||
("M001CS008", 139, 0, 1),
|
||||
("M001CS009", 140, 0, 1),
|
||||
("M001CS010", 141, 0, 1),
|
||||
("M001CS011", 142, 0, 1),
|
||||
("M001CT012", 143, 0, 8),
|
||||
("M001CV013", 144, 0, 8),
|
||||
("M001CV014", 145, 0, 8),
|
||||
("M001CV015", 146, 0, 8),
|
||||
("M001CS016", 147, 0, 1),
|
||||
("M001CS017", 148, 0, 1),
|
||||
("M001CS018", 149, 0, 1),
|
||||
("M001CS019", 150, 0, 1),
|
||||
("M001CS020", 151, 0, 1),
|
||||
("M001CS021", 152, 0, 1),
|
||||
("M001CS022", 153, 0, 1),
|
||||
("M001CV023", 154, 0, 8),
|
||||
("M001CV024", 155, 0, 8),
|
||||
("M001CT025", 156, 0, 8),
|
||||
("M001CS026", 157, 0, 1),
|
||||
("M001CI027", 158, 0, 8),
|
||||
("M001CV028", 159, 0, 8),
|
||||
("M001CV029", 160, 0, 8),
|
||||
("M001CT030", 161, 0, 8),
|
||||
("M001CS031", 162, 0, 1),
|
||||
("M001CI032", 163, 0, 8),
|
||||
("M001CT033", 164, 0, 8),
|
||||
("M001CS034", 165, 0, 1),
|
||||
("M001CS035", 166, 0, 1),
|
||||
],
|
||||
# 包2
|
||||
2: [
|
||||
("M002YI002", 132, 4, 12),
|
||||
("M002YI004", 134, 4, 12),
|
||||
("M002YI006", 136, 4, 12),
|
||||
("M002YI008", 138, 4, 12),
|
||||
("M002YI010", 140, 4, 12),
|
||||
("M002YI012", 142, 4, 12),
|
||||
("M002YI014", 144, 4, 12),
|
||||
("M002YI016", 146, 4, 12),
|
||||
("M002YV018", 148, 4, 12),
|
||||
("M002YV020", 150, 4, 12),
|
||||
("M002YV022", 152, 4, 12),
|
||||
("M002YV024", 154, 4, 12),
|
||||
("M002YS025", 156, 0, 8),
|
||||
("M002YS026", 157, 0, 8),
|
||||
("M002YS027", 158, 0, 8),
|
||||
("M002YS028", 159, 0, 8),
|
||||
("M002YS029", 160, 0, 8),
|
||||
("M002YS030", 161, 0, 8),
|
||||
("M002YS031", 162, 0, 8),
|
||||
("M002YS032", 163, 0, 8),
|
||||
("M002YS033", 164, 0, 8),
|
||||
("M002YS034", 165, 0, 8),
|
||||
("M002YS035", 166, 0, 8),
|
||||
("M002YS036", 167, 0, 8),
|
||||
("M002YI040", 170, 4, 12),
|
||||
("M002YI042", 172, 4, 12),
|
||||
("M002YI044", 174, 4, 12),
|
||||
("M002YI046", 176, 4, 12),
|
||||
("M002YI048", 178, 4, 12),
|
||||
("M002YI050", 180, 4, 12),
|
||||
("M002YI052", 182, 4, 12),
|
||||
("M002YV054", 184, 4, 12),
|
||||
("M002YV056", 186, 4, 12),
|
||||
],
|
||||
# 包3
|
||||
3: [
|
||||
("M003YI002", 132, 4, 12),
|
||||
("M003YI004", 134, 4, 12),
|
||||
("M003YG027", 156, 0, 4),
|
||||
("M003YG028", 156, 4, 4),
|
||||
("M003YG029", 157, 0, 4),
|
||||
("M003YG030", 157, 4, 4),
|
||||
("M003YI034", 160, 4, 12),
|
||||
("M003YI036", 162, 4, 12),
|
||||
],
|
||||
# 包4
|
||||
4: [
|
||||
("M004YV002", 132, 4, 12),
|
||||
("M004YV004", 134, 4, 12),
|
||||
("M004YV006", 136, 4, 12),
|
||||
("M004YV008", 138, 4, 12),
|
||||
("M004YV010", 140, 4, 12),
|
||||
("M004YV012", 142, 4, 12),
|
||||
("M004YV014", 144, 4, 12),
|
||||
("M004YV016", 146, 4, 12),
|
||||
("M004YV018", 148, 4, 12),
|
||||
("M004YV022", 152, 4, 12),
|
||||
("M004YV024", 154, 4, 12),
|
||||
("M004YV026", 156, 4, 12),
|
||||
("M004YV028", 158, 4, 12),
|
||||
("M004YV030", 160, 4, 12),
|
||||
("M004YV032", 162, 4, 12),
|
||||
("M004YV034", 164, 4, 12),
|
||||
("M004YV036", 166, 4, 12),
|
||||
("M004YV038", 168, 4, 12),
|
||||
],
|
||||
# 包18
|
||||
18: [
|
||||
("M018XV017", 164, 0, 16),
|
||||
("M018XV019", 168, 0, 16),
|
||||
],
|
||||
# 包19
|
||||
19: [
|
||||
("M019XV005", 140, 0, 16),
|
||||
],
|
||||
# 包57
|
||||
57: [
|
||||
("M057JS005", 135, 1, 1),
|
||||
("M057JS006", 135, 2, 1),
|
||||
("M057JS007", 135, 3, 1),
|
||||
("M057JS008", 135, 4, 1),
|
||||
("M057JS009", 135, 5, 1),
|
||||
("M057JS010", 135, 6, 1),
|
||||
("M057JS012", 136, 1, 1),
|
||||
("M057JS013", 136, 2, 1),
|
||||
("M057JS014", 136, 3, 3),
|
||||
("M057JS015", 136, 6, 3),
|
||||
("M057JS017", 137, 2, 1),
|
||||
("M057JS018", 137, 3, 1),
|
||||
("M057JG023", 142, 0, 16),
|
||||
("M057JG024", 144, 0, 16),
|
||||
("M057JG039", 174, 0, 32),
|
||||
("M057JG040", 178, 0, 32),
|
||||
],
|
||||
# 包79
|
||||
79: [
|
||||
("M079CG032", 148, 2, 2),
|
||||
("M079CS033", 148, 4, 1),
|
||||
("M079CS034", 148, 5, 1),
|
||||
],
|
||||
# 包85
|
||||
85: [
|
||||
("M085TV003", 135, 0, 16),
|
||||
("M085CV004", 137, 0, 16),
|
||||
],
|
||||
# 包87
|
||||
87: [
|
||||
("M087CS063", 179, 3, 1),
|
||||
("M087CS064", 179, 4, 1),
|
||||
("M087CS065", 179, 5, 1),
|
||||
("M087CS066", 179, 6, 1),
|
||||
("M087CS067", 179, 7, 1),
|
||||
("M087CS068", 180, 0, 1),
|
||||
("M087CS069", 180, 1, 1),
|
||||
("M087CS078", 181, 2, 1),
|
||||
("M087CS079", 181, 3, 1),
|
||||
],
|
||||
|
||||
# ========== 新增第二批独立包号 ==========
|
||||
# 包151
|
||||
151: [
|
||||
("M001CT001", 0, 0, 8),
|
||||
("M001CV002", 1, 0, 8),
|
||||
("M001CV003", 2, 0, 8),
|
||||
("M001CV004", 3, 0, 8),
|
||||
("M001CS005", 4, 0, 1),
|
||||
("M001CS006", 5, 0, 1),
|
||||
("M001CS007", 6, 0, 1),
|
||||
("M001CS008", 7, 0, 1),
|
||||
("M001CS009", 8, 0, 1),
|
||||
("M001CS010", 9, 0, 1),
|
||||
("M001CS011", 10, 0, 1),
|
||||
("M001CT012", 11, 0, 8),
|
||||
("M001CV013", 12, 0, 8),
|
||||
("M001CV014", 13, 0, 8),
|
||||
("M001CV015", 14, 0, 8),
|
||||
("M001CS016", 15, 0, 1),
|
||||
("M001CS017", 16, 0, 1),
|
||||
("M001CS018", 17, 0, 1),
|
||||
("M001CS019", 18, 0, 1),
|
||||
("M001CS020", 19, 0, 1),
|
||||
("M001CS021", 20, 0, 1),
|
||||
("M001CS022", 21, 0, 1),
|
||||
("M001CV023", 22, 0, 8),
|
||||
("M001CV024", 23, 0, 8),
|
||||
("M001CT025", 24, 0, 8),
|
||||
("M001CS026", 25, 0, 1),
|
||||
("M001CI027", 26, 0, 8),
|
||||
("M001CV028", 27, 0, 8),
|
||||
("M001CV029", 28, 0, 8),
|
||||
("M001CT030", 29, 0, 8),
|
||||
("M001CS031", 30, 0, 1),
|
||||
("M001CI032", 31, 0, 8),
|
||||
("M001CT033", 32, 0, 8),
|
||||
("M001CS034", 33, 0, 1),
|
||||
("M001CS035", 34, 0, 1),
|
||||
],
|
||||
# 包126
|
||||
126: [
|
||||
("M079CG032", 16, 2, 2),
|
||||
("M079CS033", 16, 4, 1),
|
||||
("M079CS034", 16, 5, 1),
|
||||
("M002YI002", 66, 4, 12),
|
||||
("M002YI004", 68, 4, 12),
|
||||
("M002YI006", 70, 4, 12),
|
||||
("M002YI008", 72, 4, 12),
|
||||
("M002YI010", 74, 4, 12),
|
||||
("M002YI012", 76, 4, 12),
|
||||
("M002YI014", 78, 4, 12),
|
||||
("M002YI016", 80, 4, 12),
|
||||
("M002YV018", 82, 4, 12),
|
||||
("M002YV020", 84, 4, 12),
|
||||
("M002YV022", 86, 4, 12),
|
||||
("M002YV024", 88, 4, 12),
|
||||
("M002YS025", 90, 0, 8),
|
||||
("M002YS026", 91, 0, 8),
|
||||
("M002YS027", 92, 0, 8),
|
||||
("M002YS028", 93, 0, 8),
|
||||
("M002YS029", 94, 0, 8),
|
||||
("M002YS030", 95, 0, 8),
|
||||
("M002YS031", 96, 0, 8),
|
||||
("M002YS032", 97, 0, 8),
|
||||
("M002YS033", 98, 0, 8),
|
||||
("M002YS034", 99, 0, 8),
|
||||
("M002YS035", 100, 0, 8),
|
||||
("M002YS036", 101, 0, 8),
|
||||
("M002YI040", 104, 4, 12),
|
||||
("M002YI042", 106, 4, 12),
|
||||
("M002YI044", 108, 4, 12),
|
||||
("M002YI046", 110, 4, 12),
|
||||
("M002YI048", 112, 4, 12),
|
||||
("M002YI050", 114, 4, 12),
|
||||
("M002YI052", 116, 4, 12),
|
||||
("M002YV054", 118, 4, 12),
|
||||
("M002YV056", 120, 4, 12),
|
||||
],
|
||||
# 包127
|
||||
127: [
|
||||
("M085TV003", 3, 0, 16),
|
||||
("M085CV004", 5, 0, 16),
|
||||
("M087CS063", 113, 3, 1),
|
||||
("M087CS064", 113, 4, 1),
|
||||
("M087CS065", 113, 5, 1),
|
||||
("M087CS066", 113, 6, 1),
|
||||
("M087CS067", 113, 7, 1),
|
||||
("M087CS068", 114, 0, 1),
|
||||
("M087CS069", 114, 1, 1),
|
||||
("M087CS078", 115, 2, 1),
|
||||
("M087CS079", 115, 3, 1),
|
||||
],
|
||||
# 包128
|
||||
128: [
|
||||
("M087CS063", 113, 3, 1),
|
||||
("M087CS064", 113, 4, 1),
|
||||
("M087CS065", 113, 5, 1),
|
||||
("M087CS066", 113, 6, 1),
|
||||
("M087CS067", 113, 7, 1),
|
||||
("M087CS068", 114, 0, 1),
|
||||
("M087CS069", 114, 1, 1),
|
||||
("M087CS078", 115, 2, 1),
|
||||
("M087CS079", 115, 3, 1),
|
||||
],
|
||||
# 包129
|
||||
129: [
|
||||
("M087CS063", 113, 3, 1),
|
||||
("M087CS064", 113, 4, 1),
|
||||
("M087CS065", 113, 5, 1),
|
||||
("M087CS066", 113, 6, 1),
|
||||
("M087CS067", 113, 7, 1),
|
||||
("M087CS068", 114, 0, 1),
|
||||
("M087CS069", 114, 1, 1),
|
||||
("M087CS078", 115, 2, 1),
|
||||
("M087CS079", 115, 3, 1),
|
||||
],
|
||||
# 包143
|
||||
143: [
|
||||
("M057JS005", 135, 1, 1),
|
||||
("M057JS006", 135, 2, 1),
|
||||
("M057JS007", 135, 3, 1),
|
||||
("M057JS008", 135, 4, 1),
|
||||
("M057JS009", 135, 5, 1),
|
||||
("M057JS010", 135, 6, 1),
|
||||
("M057JS012", 136, 1, 1),
|
||||
("M057JS013", 136, 2, 1),
|
||||
("M057JS014", 136, 3, 3),
|
||||
("M057JS015", 136, 6, 3),
|
||||
("M057JS017", 137, 2, 1),
|
||||
("M057JS018", 137, 3, 1),
|
||||
("M057JG023", 142, 0, 16),
|
||||
("M057JG024", 144, 0, 16),
|
||||
("M057JG039", 174, 0, 32),
|
||||
("M057JG040", 178, 0, 32),
|
||||
],
|
||||
# 包147
|
||||
147: [
|
||||
("M003YI002", 0, 4, 12),
|
||||
("M003YI004", 2, 4, 12),
|
||||
("M003YG027", 24, 0, 4),
|
||||
("M003YG028", 24, 4, 4),
|
||||
("M003YG029", 25, 0, 4),
|
||||
("M003YG030", 25, 4, 4),
|
||||
("M003YI034", 28, 4, 12),
|
||||
("M003YI036", 30, 4, 12),
|
||||
("M004YV002", 66, 4, 12),
|
||||
("M004YV004", 68, 4, 12),
|
||||
("M004YV006", 70, 4, 12),
|
||||
("M004YV008", 72, 4, 12),
|
||||
("M004YV010", 74, 4, 12),
|
||||
("M004YV012", 76, 4, 12),
|
||||
("M004YV014", 78, 4, 12),
|
||||
("M004YV016", 80, 4, 12),
|
||||
("M004YV018", 82, 4, 12),
|
||||
("M004YV022", 86, 4, 12),
|
||||
("M004YV024", 88, 4, 12),
|
||||
("M004YV026", 90, 4, 12),
|
||||
("M004YV028", 92, 4, 12),
|
||||
("M004YV030", 94, 4, 12),
|
||||
("M004YV032", 96, 4, 12),
|
||||
("M004YV034", 98, 4, 12),
|
||||
("M004YV036", 100, 4, 12),
|
||||
("M004YV038", 102, 4, 12),
|
||||
],
|
||||
# 包149
|
||||
149: [
|
||||
("M019XV005", 132, 0, 16),
|
||||
("M018XV017", 32, 0, 16),
|
||||
("M018XV019", 36, 0, 16),
|
||||
]
|
||||
}
|
||||
"""
|
||||
# 2026-04-19 最新版 B2C 遥测更新规则
|
||||
# 完全依据本次最新表格、所有偏移量预计算、多包拆分完成
|
||||
B2C_UPDATE_RULES = {
|
||||
# ==================== 第一组:大包号(1/2/3/4/18/19/57/79/85/87) 偏移+132 ====================
|
||||
1: [
|
||||
("M001CT001", 132, 0, 8),
|
||||
("M001CV002", 133, 0, 8),
|
||||
("M001CV003", 134, 0, 8),
|
||||
("M001CV004", 135, 0, 8),
|
||||
("M001CS005", 136, 0, 1),
|
||||
("M001CS006", 137, 0, 1),
|
||||
("M001CS007", 138, 0, 1),
|
||||
("M001CS008", 139, 0, 1),
|
||||
("M001CS009", 140, 0, 1),
|
||||
("M001CS010", 141, 0, 1),
|
||||
("M001CS011", 142, 0, 1),
|
||||
("M001CT012", 143, 0, 8),
|
||||
("M001CV013", 144, 0, 8),
|
||||
("M001CV014", 145, 0, 8),
|
||||
("M001CV015", 146, 0, 8),
|
||||
("M001CS016", 147, 0, 1),
|
||||
("M001CS017", 148, 0, 1),
|
||||
("M001CS018", 149, 0, 1),
|
||||
("M001CS019", 150, 0, 1),
|
||||
("M001CS020", 151, 0, 1),
|
||||
("M001CS021", 152, 0, 1),
|
||||
("M001CS022", 153, 0, 1),
|
||||
("M001CV023", 154, 0, 8),
|
||||
("M001CV024", 155, 0, 8),
|
||||
("M001CT025", 156, 0, 8),
|
||||
("M001CS026", 157, 0, 1),
|
||||
("M001CI027", 158, 0, 8),
|
||||
("M001CV028", 159, 0, 8),
|
||||
("M001CV029", 160, 0, 8),
|
||||
("M001CT030", 161, 0, 8),
|
||||
("M001CS031", 162, 0, 1),
|
||||
("M001CI032", 163, 0, 8),
|
||||
("M001CT033", 164, 0, 8),
|
||||
("M001CS034", 165, 0, 1),
|
||||
("M001CS035", 166, 0, 1),
|
||||
],
|
||||
2: [
|
||||
("M002YI002", 132, 4, 12),
|
||||
("M002YI004", 134, 4, 12),
|
||||
("M002YI006", 136, 4, 12),
|
||||
("M002YI008", 138, 4, 12),
|
||||
("M002YI010", 140, 4, 12),
|
||||
("M002YI012", 142, 4, 12),
|
||||
("M002YI014", 144, 4, 12),
|
||||
("M002YI016", 146, 4, 12),
|
||||
("M002YV018", 148, 4, 12),
|
||||
("M002YV020", 150, 4, 12),
|
||||
("M002YV022", 152, 4, 12),
|
||||
("M002YV024", 154, 4, 12),
|
||||
("M002YS025", 156, 0, 8),
|
||||
("M002YS026", 157, 0, 8),
|
||||
("M002YS027", 158, 0, 8),
|
||||
("M002YS028", 159, 0, 8),
|
||||
("M002YS029", 160, 0, 8),
|
||||
("M002YS030", 161, 0, 8),
|
||||
("M002YS031", 162, 0, 8),
|
||||
("M002YS032", 163, 0, 8),
|
||||
("M002YS033", 164, 0, 8),
|
||||
("M002YS034", 165, 0, 8),
|
||||
("M002YS035", 166, 0, 8),
|
||||
("M002YS036", 167, 0, 8),
|
||||
("M002YI040", 170, 4, 12),
|
||||
("M002YI042", 172, 4, 12),
|
||||
("M002YI044", 174, 4, 12),
|
||||
("M002YI046", 176, 4, 12),
|
||||
("M002YI048", 178, 4, 12),
|
||||
("M002YI050", 180, 4, 12),
|
||||
("M002YI052", 182, 4, 12),
|
||||
("M002YV054", 184, 4, 12),
|
||||
("M002YV056", 186, 4, 12),
|
||||
],
|
||||
3: [
|
||||
("M003YI002", 132, 4, 12),
|
||||
("M003YI004", 134, 4, 12),
|
||||
("M003YG027", 156, 0, 4),
|
||||
("M003YG028", 156, 4, 4),
|
||||
("M003YG029", 157, 0, 4),
|
||||
("M003YG030", 157, 4, 4),
|
||||
("M003YI034", 160, 4, 12),
|
||||
("M003YI036", 162, 4, 12),
|
||||
# ========== 【新增】包3 M003YV038 ==========
|
||||
("M003YV038", 164, 4, 12),
|
||||
],
|
||||
4: [
|
||||
("M004YV002", 132, 4, 12),
|
||||
("M004YV004", 134, 4, 12),
|
||||
("M004YV006", 136, 4, 12),
|
||||
("M004YV008", 138, 4, 12),
|
||||
("M004YV010", 140, 4, 12),
|
||||
("M004YV012", 142, 4, 12),
|
||||
("M004YV014", 144, 4, 12),
|
||||
("M004YV016", 146, 4, 12),
|
||||
("M004YV018", 148, 4, 12),
|
||||
("M004YV022", 152, 4, 12),
|
||||
("M004YV024", 154, 4, 12),
|
||||
("M004YV026", 156, 4, 12),
|
||||
("M004YV028", 158, 4, 12),
|
||||
("M004YV030", 160, 4, 12),
|
||||
("M004YV032", 162, 4, 12),
|
||||
("M004YV034", 164, 4, 12),
|
||||
("M004YV036", 166, 4, 12),
|
||||
("M004YV038", 168, 4, 12),
|
||||
],
|
||||
|
||||
# ========== 【新增】包10:M010 系列 ==========
|
||||
10: [
|
||||
("M010YV006", 136, 4, 12),
|
||||
("M010YV012", 142, 4, 12),
|
||||
("M010YV014", 144, 4, 12),
|
||||
],
|
||||
14: [
|
||||
("M014ZG027", 184, 0, 8),#2026/5/8 计算机包9
|
||||
],
|
||||
18: [
|
||||
("M018XV017", 164, 0, 16),
|
||||
("M018XV019", 168, 0, 16),
|
||||
],
|
||||
19: [
|
||||
("M019XV005", 140, 0, 16),
|
||||
],
|
||||
##2026/4/26新增50包
|
||||
50: [
|
||||
|
||||
# ("M050YV001", 132, 0, 16),
|
||||
# ("M050YV002", 134, 0, 16),
|
||||
# ("M050YV003", 136, 0, 16),#阈值先不动
|
||||
("M050YS055", 171, 0, 1),
|
||||
("M050YS056", 171, 1, 1),
|
||||
("M050YS057", 171, 2, 1),
|
||||
("M050YS058", 171, 3, 1),#2026/5/8
|
||||
("M050YS067", 186, 0, 2),#2026/5/8
|
||||
("M050YS068", 186, 1, 2),#2026/5/8
|
||||
("M050YS069", 186, 2, 2),#2026/5/8
|
||||
("M050YS070", 186, 3, 2),#2026/5/8
|
||||
("M050YG073", 186, 6, 2),
|
||||
|
||||
],
|
||||
|
||||
57: [
|
||||
("M057JS005", 135, 1, 1),
|
||||
("M057JS006", 135, 2, 1),
|
||||
("M057JS007", 135, 3, 1),
|
||||
("M057JS008", 135, 4, 1),
|
||||
("M057JS009", 135, 5, 1),
|
||||
("M057JS010", 135, 6, 1),
|
||||
# ("M057JS012", 136, 1, 1),
|
||||
# ("M057JS013", 136, 2, 1),
|
||||
("M057JS014", 136, 3, 3),
|
||||
("M057JS015", 136, 6, 3),
|
||||
("M057JS017", 137, 2, 1),
|
||||
("M057JS018", 137, 3, 1),
|
||||
#("M057JG023", 142, 0, 16),
|
||||
#("M057JG024", 144, 0, 16),
|
||||
#("M057JG039", 174, 0, 32),
|
||||
#("M057JG040", 178, 0, 32),
|
||||
],
|
||||
79: [
|
||||
("M079CG032", 148, 2, 2),
|
||||
("M079CS033", 148, 4, 1),
|
||||
("M079CS034", 148, 5, 1),
|
||||
],
|
||||
85: [
|
||||
("M085TV003", 135, 0, 16),
|
||||
("M085CV004", 137, 0, 16),
|
||||
],
|
||||
87: [
|
||||
("M087CS063", 179, 3, 1),
|
||||
("M087CS064", 179, 4, 1),
|
||||
("M087CS065", 179, 5, 1),
|
||||
("M087CS066", 179, 6, 1),
|
||||
("M087CS067", 179, 7, 1),
|
||||
("M087CS068", 180, 0, 1),
|
||||
("M087CS069", 180, 1, 1),
|
||||
("M087CS078", 181, 2, 1),
|
||||
("M087CS079", 181, 3, 1),
|
||||
],
|
||||
|
||||
# ==================== 第二组:专项包号(151/126/127/128/129/143/147/149) 新偏移 ====================
|
||||
151: [
|
||||
("M001CT001", 4, 0, 8),
|
||||
("M001CV002", 5, 0, 8),
|
||||
("M001CV003", 6, 0, 8),
|
||||
("M001CV004", 7, 0, 8),
|
||||
("M001CS005", 8, 0, 1),
|
||||
("M001CS006", 9, 0, 1),
|
||||
("M001CS007", 10, 0, 1),
|
||||
("M001CS008", 11, 0, 1),
|
||||
("M001CS009", 12, 0, 1),
|
||||
("M001CS010", 13, 0, 1),
|
||||
("M001CS011", 14, 0, 1),
|
||||
("M001CT012", 15, 0, 8),
|
||||
("M001CV013", 16, 0, 8),
|
||||
("M001CV014", 17, 0, 8),
|
||||
("M001CV015", 18, 0, 8),
|
||||
("M001CS016", 19, 0, 1),
|
||||
("M001CS017", 20, 0, 1),
|
||||
("M001CS018", 21, 0, 1),
|
||||
("M001CS019", 22, 0, 1),
|
||||
("M001CS020", 23, 0, 1),
|
||||
("M001CS021", 24, 0, 1),
|
||||
("M001CS022", 25, 0, 1),
|
||||
("M001CV023", 26, 0, 8),
|
||||
("M001CV024", 27, 0, 8),
|
||||
("M001CT025", 28, 0, 8),
|
||||
("M001CS026", 29, 0, 1),
|
||||
("M001CI027", 30, 0, 8),
|
||||
("M001CV028", 31, 0, 8),
|
||||
("M001CV029", 32, 0, 8),
|
||||
("M001CT030", 33, 0, 8),
|
||||
("M001CS031", 34, 0, 1),
|
||||
("M001CI032", 35, 0, 8),
|
||||
("M001CT033", 36, 0, 8),
|
||||
("M001CS034", 37, 0, 1),
|
||||
("M001CS035", 38, 0, 1),
|
||||
],
|
||||
|
||||
125: [
|
||||
("M014ZG027", 184, 0, 8),#2026/5/8 计算机包9
|
||||
],
|
||||
|
||||
126: [
|
||||
("M079CG032", 20, 2, 2),
|
||||
("M079CS033", 20, 4, 1),
|
||||
("M079CS034", 20, 5, 1),
|
||||
("M002YI002", 68, 4, 12),
|
||||
("M002YI004", 70, 4, 12),
|
||||
("M002YI006", 72, 4, 12),
|
||||
("M002YI008", 74, 4, 12),
|
||||
("M002YI010", 76, 4, 12),
|
||||
("M002YI012", 78, 4, 12),
|
||||
("M002YI014", 80, 4, 12),
|
||||
("M002YI016", 82, 4, 12),
|
||||
("M002YV018", 84, 4, 12),
|
||||
("M002YV020", 86, 4, 12),
|
||||
("M002YV022", 88, 4, 12),
|
||||
("M002YV024", 90, 4, 12),
|
||||
("M002YS025", 92, 0, 8),
|
||||
("M002YS026", 93, 0, 8),
|
||||
("M002YS027", 94, 0, 8),
|
||||
("M002YS028", 95, 0, 8),
|
||||
("M002YS029", 96, 0, 8),
|
||||
("M002YS030", 97, 0, 8),
|
||||
("M002YS031", 98, 0, 8),
|
||||
("M002YS032", 99, 0, 8),
|
||||
("M002YS033", 100, 0, 8),
|
||||
("M002YS034", 101, 0, 8),
|
||||
("M002YS035", 102, 0, 8),
|
||||
("M002YS036", 101, 0, 8),
|
||||
("M002YI040", 106, 4, 12),
|
||||
("M002YI042", 108, 4, 12),
|
||||
("M002YI044", 110, 4, 12),
|
||||
("M002YI046", 112, 4, 12),
|
||||
("M002YI048", 114, 4, 12),
|
||||
("M002YI050", 116, 4, 12),
|
||||
("M002YI052", 118, 4, 12),
|
||||
("M002YV054", 120, 4, 12),
|
||||
("M002YV056", 122, 4, 12),
|
||||
],
|
||||
127: [
|
||||
("M085TV003", 7, 0, 16),
|
||||
("M085CV004", 9, 0, 16),
|
||||
("M087CS063", 115, 3, 1),
|
||||
("M087CS064", 115, 4, 1),
|
||||
("M087CS065", 115, 5, 1),
|
||||
("M087CS066", 115, 6, 1),
|
||||
("M087CS067", 115, 7, 1),
|
||||
("M087CS068", 116, 0, 1),
|
||||
("M087CS069", 116, 1, 1),
|
||||
("M087CS078", 117, 2, 1),
|
||||
("M087CS079", 117, 3, 1),
|
||||
],
|
||||
128: [
|
||||
("M087CS063", 115, 3, 1),
|
||||
("M087CS064", 115, 4, 1),
|
||||
("M087CS065", 115, 5, 1),
|
||||
("M087CS066", 115, 6, 1),
|
||||
("M087CS067", 115, 7, 1),
|
||||
("M087CS068", 116, 0, 1),
|
||||
("M087CS069", 116, 1, 1),
|
||||
("M087CS078", 117, 2, 1),
|
||||
("M087CS079", 117, 3, 1),
|
||||
],
|
||||
129: [
|
||||
("M087CS063", 115, 3, 1),
|
||||
("M087CS064", 115, 4, 1),
|
||||
("M087CS065", 115, 5, 1),
|
||||
("M087CS066", 115, 6, 1),
|
||||
("M087CS067", 115, 7, 1),
|
||||
("M087CS068", 116, 0, 1),
|
||||
("M087CS069", 116, 1, 1),
|
||||
("M087CS078", 117, 2, 1),
|
||||
("M087CS079", 117, 3, 1),
|
||||
],
|
||||
143: [
|
||||
("M057JS005", 135, 1, 1),
|
||||
("M057JS006", 135, 2, 1),
|
||||
("M057JS007", 135, 3, 1),
|
||||
("M057JS008", 135, 4, 1),
|
||||
("M057JS009", 135, 5, 1),
|
||||
("M057JS010", 135, 6, 1),
|
||||
# ("M057JS012", 136, 1, 1),
|
||||
# ("M057JS013", 136, 2, 1),
|
||||
("M057JS014", 136, 3, 3),
|
||||
("M057JS015", 136, 6, 3),
|
||||
("M057JS017", 137, 2, 1),
|
||||
("M057JS018", 137, 3, 1),
|
||||
#("M057JG023", 142, 0, 16),
|
||||
#("M057JG024", 144, 0, 16),
|
||||
#("M057JG039", 174, 0, 32),
|
||||
#("M057JG040", 178, 0, 32),
|
||||
],
|
||||
147: [
|
||||
("M003YI002", 4, 4, 12),
|
||||
("M003YI004", 6, 4, 12),
|
||||
("M003YG027", 28, 0, 4),
|
||||
("M003YG028", 28, 4, 4),
|
||||
("M003YG029", 29, 0, 4),
|
||||
("M003YG030", 29, 4, 4),
|
||||
("M003YI034", 32, 4, 12),
|
||||
("M003YI036", 34, 4, 12),
|
||||
# ========== 【新增】包147 M003YV038 ==========
|
||||
("M003YV038", 36, 4, 12),
|
||||
("M004YV002", 68, 4, 12),
|
||||
("M004YV004", 70, 4, 12),
|
||||
("M004YV006", 72, 4, 12),
|
||||
("M004YV008", 74, 4, 12),
|
||||
("M004YV010", 76, 4, 12),
|
||||
("M004YV012", 78, 4, 12),
|
||||
("M004YV014", 80, 4, 12),
|
||||
("M004YV016", 82, 4, 12),
|
||||
("M004YV018", 84, 4, 12),
|
||||
("M004YV022", 88, 4, 12),
|
||||
("M004YV024", 90, 4, 12),
|
||||
("M004YV026", 92, 4, 12),
|
||||
("M004YV028", 94, 4, 12),
|
||||
("M004YV030", 96, 4, 12),
|
||||
("M004YV032", 98, 4, 12),
|
||||
("M004YV034", 100, 4, 12),
|
||||
("M004YV036", 102, 4, 12),
|
||||
("M004YV038", 104, 4, 12),
|
||||
## 2026/4/26
|
||||
# ("M050YV001", 132, 0, 16),
|
||||
# ("M050YV002", 134, 0, 16),
|
||||
# ("M050YV003", 136, 0, 16),#阈值先不修改
|
||||
("M050YS055", 171, 0, 1),
|
||||
("M050YS056", 171, 1, 1),
|
||||
("M050YS057", 171, 2, 1),
|
||||
("M050YS058", 171, 3, 1),#2026/5/8
|
||||
("M050YS067", 186, 0, 2),#2026/5/8
|
||||
("M050YS068", 186, 1, 2),#2026/5/8
|
||||
("M050YS069", 186, 2, 2),#2026/5/8
|
||||
("M050YS070", 186, 3, 2),#2026/5/8
|
||||
("M050YG073", 186, 6, 2),
|
||||
],
|
||||
149: [
|
||||
("M019XV005", 76, 0, 16),
|
||||
("M018XV017", 36, 0, 16),
|
||||
("M018XV019", 40, 0, 16),
|
||||
],
|
||||
|
||||
# ========== 【新增】包162:M010 系列 ==========
|
||||
162: [
|
||||
("M010YV006", 8, 4, 12),
|
||||
("M010YV012", 14, 4, 12),
|
||||
("M010YV014", 16, 4, 12),
|
||||
],
|
||||
}
|
||||
36
core/b_gis_client.py
Normal file
36
core/b_gis_client.py
Normal file
@@ -0,0 +1,36 @@
|
||||
import socket
|
||||
import time
|
||||
from utils.logger import logger
|
||||
|
||||
class BGisClient:
|
||||
def __init__(self, b_ip, b_port):
|
||||
self.b_ip = b_ip
|
||||
self.b_port = b_port
|
||||
self.sock = None
|
||||
self.connected = False
|
||||
|
||||
def connect(self):
|
||||
while True:
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(3)
|
||||
sock.connect((self.b_ip, self.b_port))
|
||||
self.sock = sock
|
||||
self.connected = True
|
||||
logger.info(f"✅ B 地测端口连接成功:{self.b_ip}:{self.b_port}")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"❌ B 地测端口连接失败,重试:{e}")
|
||||
time.sleep(1)
|
||||
|
||||
def send(self, data):
|
||||
if not self.connected:
|
||||
self.connect()
|
||||
return
|
||||
|
||||
try:
|
||||
self.sock.sendall(data)
|
||||
except Exception as e:
|
||||
logger.error(f"❌ B 地测发送失败:{e}")
|
||||
self.connected = False
|
||||
self.sock = None
|
||||
31
core/bit_packer.py
Normal file
31
core/bit_packer.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
2026/4/5
|
||||
TMY
|
||||
比特位打包器
|
||||
"""
|
||||
class BitPacker:
|
||||
def __init__(self, total_bytes):
|
||||
self.buf = bytearray(total_bytes)
|
||||
|
||||
def set_bits(self, start_byte, start_bit, bit_len, value):
|
||||
"""
|
||||
start_byte: 起始字节
|
||||
start_bit: 起始比特位(0~7)
|
||||
bit_len: 比特长度
|
||||
value: 无符号整数值
|
||||
"""
|
||||
value = int(value) & ((1 << bit_len) - 1)
|
||||
bit_pos = start_byte * 8 + start_bit
|
||||
|
||||
for i in range(bit_len):
|
||||
bit = (value >> (bit_len - 1 - i)) & 1
|
||||
byte_idx = bit_pos // 8
|
||||
bit_idx = 7 - (bit_pos % 8)
|
||||
if bit:
|
||||
self.buf[byte_idx] |= (1 << bit_idx)
|
||||
else:
|
||||
self.buf[byte_idx] &= ~(1 << bit_idx)
|
||||
bit_pos += 1
|
||||
|
||||
def get_bytes(self):
|
||||
return bytes(self.buf)
|
||||
34
core/bit_tools.py
Normal file
34
core/bit_tools.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""
|
||||
2026/4/18
|
||||
Tan Mingyan
|
||||
新建 比特 / 字节 操作工具(通用、精准)
|
||||
"""
|
||||
def set_bits(data: bytearray, byte_offset: int, bit_offset: int, bit_length: int, value: int):
|
||||
"""
|
||||
对字节数组指定位置写入指定位数的值
|
||||
:param data: 原始字节数组(会被修改)
|
||||
:param byte_offset: 起始字节(从0开始,用户数据域起始为0)
|
||||
:param bit_offset: 起始比特(0~7)
|
||||
:param bit_length: 占多少比特
|
||||
:param value: 要写入的值
|
||||
"""
|
||||
if byte_offset >= len(data):
|
||||
return
|
||||
|
||||
# 生成掩码
|
||||
max_val = (1 << bit_length) - 1
|
||||
value = value & max_val
|
||||
|
||||
pos = byte_offset * 8 + bit_offset
|
||||
for i in range(bit_length):
|
||||
bit = (value >> (bit_length - 1 - i)) & 1
|
||||
byte_idx = pos // 8
|
||||
bit_idx = pos % 8
|
||||
|
||||
if byte_idx >= len(data):
|
||||
break
|
||||
|
||||
# 清位 + 置位
|
||||
data[byte_idx] &= ~(1 << (7 - bit_idx))
|
||||
data[byte_idx] |= (bit << (7 - bit_idx))
|
||||
pos += 1
|
||||
198
core/f_to_a_forward.py
Normal file
198
core/f_to_a_forward.py
Normal file
@@ -0,0 +1,198 @@
|
||||
"""
|
||||
2026/4/11
|
||||
TMY
|
||||
新建 F→A 转发核心
|
||||
"""
|
||||
# import socket
|
||||
# import struct
|
||||
# from utils.logger import logger
|
||||
# from config_loader import cfg
|
||||
|
||||
# # A 帧固定头
|
||||
# SYNC_HEADER = b'\xEB\x90\xEB\x90'
|
||||
# TAIL = b'\x4C\x3A'
|
||||
|
||||
# # 固定配置
|
||||
# DIR = 0x01111111
|
||||
# DATA_ID = 0x00110000
|
||||
# TYPE = 0x00444444
|
||||
# SAT_ID = 0x000000ED
|
||||
# DATA_LEN = 0x00000004 # 固定4个double
|
||||
|
||||
# class FToAForward:
|
||||
# def __init__(self, local_port, a_ip, a_port):
|
||||
# self.local_port = local_port
|
||||
# self.a_ip = a_ip
|
||||
# self.a_port = a_port
|
||||
|
||||
# # 监听 F UDP
|
||||
# self.sock_f = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# self.sock_f.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
# self.sock_f.bind(('0.0.0.0', self.local_port))
|
||||
|
||||
# # 发往 A UDP
|
||||
# self.sock_a = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# logger.info(f"✅ F→A 转发启动:监听 F UDP {self.local_port} → A {a_ip}:{a_port}")
|
||||
|
||||
# def build_a_frame(self, shadow, sbx, sby, sbz):
|
||||
# """组 A 软件协议帧"""
|
||||
# frame = bytearray()
|
||||
# frame += SYNC_HEADER
|
||||
# frame += DATA_LEN.to_bytes(4, 'big')
|
||||
# frame += DIR.to_bytes(4, 'big')
|
||||
# frame += DATA_ID.to_bytes(4, 'big')
|
||||
# frame += TYPE.to_bytes(4, 'big')
|
||||
# frame += SAT_ID.to_bytes(4, 'big')
|
||||
|
||||
# # 4个 double 大端序
|
||||
# frame += struct.pack('>d', shadow)
|
||||
# frame += struct.pack('>d', sbx)
|
||||
# frame += struct.pack('>d', sby)
|
||||
# frame += struct.pack('>d', sbz)
|
||||
|
||||
# frame += TAIL
|
||||
# logger.info(f"F->A 帧内容: {frame}")
|
||||
# return bytes(frame)
|
||||
|
||||
# def loop(self):
|
||||
# while True:
|
||||
# data, addr = self.sock_f.recvfrom(4096)
|
||||
|
||||
# # 1. 只处理长度 2792
|
||||
# if len(data) != 2792:
|
||||
# continue
|
||||
|
||||
# # 2. 去头48,去尾8 → 2736
|
||||
# payload = data[48 : -8]
|
||||
# if len(payload) != 2736:
|
||||
# continue
|
||||
|
||||
# try:
|
||||
# # 3. 小端解析所有 double
|
||||
# doubles = []
|
||||
# for i in range(0, 2736, 8):
|
||||
# d = struct.unpack('<d', payload[i:i+8])[0]
|
||||
# doubles.append(d)
|
||||
|
||||
# # 4. 提取(从0开始,所以第30个 → 索引29)
|
||||
# shadow = doubles[29] # 第30个
|
||||
# sbx = doubles[318] # 319
|
||||
# sby = doubles[319] # 320
|
||||
# sbz = doubles[320] # 321
|
||||
# logger.info(f"shadow={shadow}, sbx={sbx}, sby={sby}, sbz={sbz}")
|
||||
# # shadow=0 → 全部置0
|
||||
# # if shadow == 0:
|
||||
# # sbx = 0.0
|
||||
# # sby = 0.0
|
||||
# # sbz = 0.0
|
||||
|
||||
# # 5. 组帧并发送
|
||||
# a_frame = self.build_a_frame(shadow, sbx, sby, sbz)
|
||||
# self.sock_a.sendto(a_frame, (self.a_ip, self.a_port))
|
||||
|
||||
# except Exception as e:
|
||||
# logger.error(f"F→A 解析失败: {e}")
|
||||
|
||||
import socket
|
||||
import struct
|
||||
import time
|
||||
from utils.hex_helper import hex_dump
|
||||
from utils.logger import logger
|
||||
|
||||
# A 帧固定头
|
||||
SYNC_HEADER = b'\xEB\x90\xEB\x90'
|
||||
TAIL = b'\x4C\x3A'
|
||||
|
||||
# 固定配置
|
||||
DIR = 0x01111111
|
||||
DATA_ID = 0x00110000
|
||||
TYPE = 0x00444444
|
||||
SAT_ID = 0x000000ED
|
||||
DATA_LEN = 0x00000004 # 4个double
|
||||
|
||||
|
||||
class FToAForward:
|
||||
def __init__(self, f_ip, f_port, a_ip, a_port):
|
||||
self.f_ip = f_ip
|
||||
self.f_port = f_port
|
||||
self.a_ip = a_ip
|
||||
self.a_port = a_port
|
||||
|
||||
self.sock_f = None
|
||||
self.sock_a = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
logger.info(f"✅ F→A 转发启动:TCP客户端连接 {f_ip}:{f_port} → A {a_ip}:{a_port}")
|
||||
|
||||
def connect_f(self):
|
||||
while True:
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(5)
|
||||
sock.connect((self.f_ip, self.f_port))
|
||||
self.sock_f = sock
|
||||
logger.info(f"✅ 成功连接 F TCP Server:{self.f_ip}:{self.f_port}")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 连接 F 失败,重试:{e}")
|
||||
time.sleep(1)
|
||||
|
||||
def build_a_frame(self, shadow, sbx, sby, sbz):
|
||||
frame = bytearray()
|
||||
frame += SYNC_HEADER
|
||||
frame += DATA_LEN.to_bytes(4, 'big')
|
||||
frame += DIR.to_bytes(4, 'big')
|
||||
frame += DATA_ID.to_bytes(4, 'big')
|
||||
frame += TYPE.to_bytes(4, 'big')
|
||||
frame += SAT_ID.to_bytes(4, 'big')
|
||||
|
||||
frame += struct.pack('>d', shadow)
|
||||
frame += struct.pack('>d', sbx)
|
||||
frame += struct.pack('>d', sby)
|
||||
frame += struct.pack('>d', sbz)
|
||||
|
||||
frame += TAIL
|
||||
#logger.info(f"F->A 帧内容: {bytes(frame)}")
|
||||
hex_dump(frame, "发送 F->A遥测帧")
|
||||
return bytes(frame)
|
||||
|
||||
def loop(self):
|
||||
while True:
|
||||
if self.sock_f is None:
|
||||
self.connect_f()
|
||||
|
||||
try:
|
||||
data = self.sock_f.recv(4096)
|
||||
if not data:
|
||||
logger.error("❌ F 断开连接,重连...")
|
||||
self.sock_f = None
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
if len(data) != 2792:
|
||||
continue
|
||||
logger.info("收到F软件发送的长度2792数据...")
|
||||
payload = data[48:-8]
|
||||
if len(payload) != 2736:
|
||||
continue
|
||||
|
||||
doubles = []
|
||||
for i in range(0, 2736, 8):
|
||||
d = struct.unpack('<d', payload[i:i+8])[0]
|
||||
doubles.append(d)
|
||||
|
||||
shadow = doubles[29]
|
||||
sbx = doubles[318]
|
||||
sby = doubles[319]
|
||||
sbz = doubles[320]
|
||||
|
||||
# if shadow == 0:
|
||||
# sbx = 0.0
|
||||
# sby = 0.0
|
||||
# sbz = 0.0
|
||||
logger.info(f"shadow={shadow}, sbx={sbx}, sby={sby}, sbz={sbz}")
|
||||
a_frame = self.build_a_frame( sbx, sby, sbz, shadow)
|
||||
self.sock_a.sendto(a_frame, (self.a_ip, self.a_port))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ F 接收异常:{e}")
|
||||
self.sock_f = None
|
||||
time.sleep(1)
|
||||
435
core/forward_engine.py
Normal file
435
core/forward_engine.py
Normal file
@@ -0,0 +1,435 @@
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
from utils.logger import logger
|
||||
from utils.hex_helper import hex_dump
|
||||
from core.tcp_forward_client import TcpForwardClient # 新增
|
||||
from core.global_params import get_param
|
||||
from core.b2c_update_rules import B2C_UPDATE_RULES
|
||||
from core.bit_tools import set_bits
|
||||
|
||||
class UdpForward:
|
||||
def __init__(self, local_port, remote_ip, remote_port, converter):
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.sock.bind(("0.0.0.0", local_port))
|
||||
self.remote = (remote_ip, remote_port)
|
||||
self.converter = converter
|
||||
|
||||
def loop(self):
|
||||
logger.info(f"UDP监听 :{self.sock.getsockname()[1]} → {self.remote}")
|
||||
while True:
|
||||
data, addr = self.sock.recvfrom(4096)
|
||||
hex_dump(data, f"UDP接收 {addr}")
|
||||
out = self.converter.convert(data)
|
||||
if out:
|
||||
self.sock.sendto(out, self.remote)
|
||||
|
||||
"""#2026/3/31 C软件使用UDP协议后停用
|
||||
class Tcp2UdpForward:
|
||||
'''
|
||||
原有功能:B → 格式转换 → D
|
||||
新增功能:B → 无条件同时转发 → C
|
||||
实现 1 发 2
|
||||
'''
|
||||
# def __init__(self, remote_tcp_ip, remote_tcp_port, udp_ip, udp_port, converter):
|
||||
# self.tcp_ip = remote_tcp_ip
|
||||
# self.tcp_port = remote_tcp_port
|
||||
# self.udp_ip = udp_ip
|
||||
# self.udp_port = udp_port
|
||||
# self.converter = converter
|
||||
# self.sock = None
|
||||
def __init__(self, remote_tcp_ip, remote_tcp_port,
|
||||
udp_ip, udp_port, converter,
|
||||
forward_c_ip=None, forward_c_port=None): # 新增 C 地址
|
||||
|
||||
self.remote_tcp_ip = remote_tcp_ip
|
||||
self.remote_tcp_port = remote_tcp_port
|
||||
self.udp_ip = udp_ip
|
||||
self.udp_port = udp_port
|
||||
self.converter = converter
|
||||
# ===================== 新增:转发C =====================
|
||||
self.forward_c = None
|
||||
if forward_c_ip and forward_c_port:
|
||||
self.forward_c = TcpForwardClient(forward_c_ip, forward_c_port)
|
||||
|
||||
self.udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
|
||||
# def connect(self):
|
||||
# while True:
|
||||
# try:
|
||||
# self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# self.sock.connect((self.tcp_ip, self.tcp_port))
|
||||
# logger.info(f"TCP连接B成功 {self.tcp_ip}:{self.tcp_port}")
|
||||
# return
|
||||
# except:
|
||||
# import time
|
||||
# time.sleep(1)
|
||||
|
||||
# def loop(self):
|
||||
# self.connect()
|
||||
# udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# while True:
|
||||
# data = self.sock.recv(4096)
|
||||
# if not data:
|
||||
# self.connect()
|
||||
# continue
|
||||
# hex_dump(data, "TCP接收B")
|
||||
# out = self.converter.convert(data)
|
||||
# if out:
|
||||
# udp.sendto(out, (self.udp_ip, self.udp_port))
|
||||
def connect_b(self):
|
||||
while True:
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.connect((self.remote_tcp_ip, self.remote_tcp_port))
|
||||
logger.info(f"✅ 连接 B 软件成功: {self.remote_tcp_ip}:{self.remote_tcp_port}")
|
||||
return sock
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 连接 B 失败,重连中: {e}")
|
||||
threading.Event().wait(2)
|
||||
|
||||
def loop(self):
|
||||
# 如果需要转发C,先连接C
|
||||
if self.forward_c:
|
||||
self.forward_c.connect()
|
||||
|
||||
while True:
|
||||
sock_tcp = self.connect_b()
|
||||
try:
|
||||
while True:
|
||||
data = sock_tcp.recv(4096)
|
||||
if not data:
|
||||
break
|
||||
|
||||
hex_dump(data, "收到 B 软件遥测帧")
|
||||
|
||||
# ===================== 核心:1 分 2 =====================
|
||||
# 1) 原有逻辑:转换后发给 D
|
||||
d_data = self.converter.convert(data)
|
||||
if d_data:
|
||||
self.udp_sock.sendto(d_data, (self.udp_ip, self.udp_port))
|
||||
|
||||
# 2) 新增逻辑:无条件原样发给 C
|
||||
if self.forward_c:
|
||||
self.forward_c.send(data)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"B 连接异常: {e}")
|
||||
finally:
|
||||
sock_tcp.close()
|
||||
"""
|
||||
"""
|
||||
class Tcp2UdpForward:#2026/4/2 B软件TC,TM双端后停用
|
||||
'''
|
||||
B → D(格式转换 UDP)
|
||||
B → C(原样 UDP 转发)
|
||||
1发2 同时输出
|
||||
'''
|
||||
def __init__(self, remote_tcp_ip, remote_tcp_port,
|
||||
udp_ip, udp_port, converter,
|
||||
forward_c_ip=None, forward_c_port=None):
|
||||
|
||||
self.remote_tcp_ip = remote_tcp_ip
|
||||
self.remote_tcp_port = remote_tcp_port
|
||||
self.udp_ip = udp_ip
|
||||
self.udp_port = udp_port
|
||||
self.converter = converter
|
||||
|
||||
# D 端 UDP
|
||||
self.udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
# ===================== C 端 UDP 转发(新版) =====================
|
||||
self.forward_c_ip = forward_c_ip
|
||||
self.forward_c_port = forward_c_port
|
||||
self.udp_c_sock = None
|
||||
if self.forward_c_ip and self.forward_c_port:
|
||||
self.udp_c_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
def connect_b(self):
|
||||
while True:
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.connect((self.remote_tcp_ip, self.remote_tcp_port))
|
||||
logger.info(f"✅ 连接 B 软件成功: {self.remote_tcp_ip}:{self.remote_tcp_port}")
|
||||
return sock
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 连接 B 失败,重连中...")
|
||||
threading.Event().wait(2)
|
||||
|
||||
def loop(self):
|
||||
while True:
|
||||
sock_tcp = self.connect_b()
|
||||
try:
|
||||
while True:
|
||||
data = sock_tcp.recv(4096)
|
||||
if not data:
|
||||
break
|
||||
|
||||
hex_dump(data, "✅ 收到 B 软件遥测帧")
|
||||
|
||||
# ========== 1. 原有逻辑:转换后发给 D ==========
|
||||
d_data = self.converter.convert(data)
|
||||
if d_data:
|
||||
self.udp_sock.sendto(d_data, (self.udp_ip, self.udp_port))
|
||||
|
||||
# ========== 2. 新增逻辑:UDP 原样发给 C ==========
|
||||
if self.udp_c_sock:
|
||||
self.udp_c_sock.sendto(data, (self.forward_c_ip, self.forward_c_port))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"⚠️ B 连接异常: {e}")
|
||||
finally:
|
||||
sock_tcp.close()
|
||||
"""
|
||||
import socket
|
||||
import threading
|
||||
from utils.logger import logger
|
||||
from utils.hex_helper import hex_dump
|
||||
from core.a2b_forward import A2BForward
|
||||
|
||||
|
||||
cmd_K6466 = "EB9001073500EB90B571A50911C00100E505F4ED4500000000000000000000000000000000000000000000000000000000DDAAAAAAAA88880C1B0C02024477A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5CCCCCCCCCCCCCCCCB2EBA5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5DF0B91945716"
|
||||
cmd_K6466_byte = bytes.fromhex(cmd_K6466)
|
||||
|
||||
class Tcp2UdpForward:
|
||||
"""
|
||||
功能:
|
||||
1. B 遥测(3078 TCP Server) → M 客户端接收
|
||||
2. 转换格式 → D(UDP)
|
||||
3. 无条件原样 → C(UDP)
|
||||
"""
|
||||
def __init__(self, b_ip, b_telem_port, udp_d_ip, udp_d_port, converter, c_ip, c_port, g_ip, g_port, g_cmd_ip, g_cmd_port, e_ip, e_port):
|
||||
self.b_ip = b_ip
|
||||
self.b_telem_port = b_telem_port # 3078
|
||||
self.d_ip = udp_d_ip
|
||||
self.d_port = udp_d_port
|
||||
self.c_ip = c_ip
|
||||
self.c_port = c_port
|
||||
self.g_ip = g_ip
|
||||
self.g_port = g_port
|
||||
self.g_cmd_ip = g_cmd_ip
|
||||
self.g_cmd_port = g_cmd_port
|
||||
self.converter = converter
|
||||
self.e_ip = e_ip
|
||||
self.e_port = e_port
|
||||
|
||||
# UDP 发送 socket
|
||||
self.udp_d = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.udp_c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.udp_g = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.udp_g_cmd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.udp_e = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
self.sock_b = None #2026/4/16修复休眠断开
|
||||
self.connected = False #2026/4/16修复休眠断开
|
||||
self.not_received_count = 0 #没有收到遥测帧次数
|
||||
|
||||
# def connect_b_telem(self):#2026/4/16弃用,不能保证断联后重新连接
|
||||
# """连接 B 遥测 TCP Server 3078"""
|
||||
# while True:
|
||||
# try:
|
||||
# sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# logger.info(f"✅ B ip,remote——port{self.b_ip,self.b_telem_port}")
|
||||
# sock.connect((self.b_ip, self.b_telem_port))
|
||||
|
||||
# logger.info(f"✅ 已连接 B 遥测端口 3078")
|
||||
# return sock
|
||||
# except Exception as e:
|
||||
# logger.error("❌ 连接 B 3078 失败,重试中...")
|
||||
# threading.Event().wait(2)
|
||||
|
||||
def connect_b_telem(self):#2026/4/16启用,修复休眠断开重连
|
||||
while True:
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(1)
|
||||
ret = s.connect_ex((self.b_ip, self.b_telem_port))
|
||||
if ret == 0:
|
||||
self.sock_b = s
|
||||
self.b_connected = True
|
||||
logger.info(f"✅ 连接 B 遥测端口成功: {self.b_ip}:{self.b_telem_port}")
|
||||
return
|
||||
except:
|
||||
pass
|
||||
logger.error(f"❌ B 遥测端口连接失败,重试...")
|
||||
time.sleep(1)
|
||||
"""
|
||||
def connect_b_telem(self):#2026/4/16启用,修复休眠断开重连
|
||||
while True:
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(5)
|
||||
s.connect((self.b_ip, self.b_telem_port))
|
||||
self.sock_f = s
|
||||
logger.info(f"✅ 连接 B 遥测端口成功: {self.b_ip}:{self.b_telem_port}")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"❌ B 遥测 连接失败,重试...")
|
||||
time.sleep(1)
|
||||
"""
|
||||
"""
|
||||
def loop(self):#2026/4/16停用,不能修复休眠断开重连
|
||||
while True:
|
||||
sock_b = self.connect_b_telem()
|
||||
try:
|
||||
while True:
|
||||
data = sock_b.recv(4096)
|
||||
if not data:
|
||||
break
|
||||
|
||||
hex_dump(data, "📥 收到 B 遥测帧")
|
||||
|
||||
# 1. 转换后发 D
|
||||
d_data = self.converter.convert(data)
|
||||
if d_data:
|
||||
self.udp_d.sendto(d_data, (self.d_ip, self.d_port))
|
||||
|
||||
# 2. 原样发 C
|
||||
self.udp_c.sendto(data, (self.c_ip, self.c_port))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"⚠️ B 遥测链路异常: {e}")
|
||||
finally:
|
||||
sock_b.close()
|
||||
"""
|
||||
|
||||
"""
|
||||
def loop(self):#2026/4/16启动,修复休眠断开重连
|
||||
while True:
|
||||
|
||||
if self.sock_b is None:
|
||||
self.connect_b_telem()
|
||||
try:
|
||||
|
||||
data = self.sock_b.recv(4096)
|
||||
if not data:
|
||||
break
|
||||
|
||||
hex_dump(data, "📥 收到 B 遥测帧")
|
||||
|
||||
# 1. 转换后发 D
|
||||
d_data = self.converter.convert(data)
|
||||
if d_data:
|
||||
self.udp_d.sendto(d_data, (self.d_ip, self.d_port))
|
||||
|
||||
# 2. 原样发 C
|
||||
self.udp_c.sendto(data, (self.c_ip, self.c_port))
|
||||
|
||||
except:
|
||||
self.sock_b = None
|
||||
logger.error(f"⚠️ B 遥测链路异常: ")
|
||||
time.sleep(1)
|
||||
"""
|
||||
|
||||
|
||||
def update_telem_frame(self, frame):#2026/4/19
|
||||
"""根据全局变量修改遥测帧(你新需求的核心)"""
|
||||
if len(frame) < 84:
|
||||
return frame
|
||||
|
||||
# 包代号在 B[83](从0开始)
|
||||
pkt_id = frame[83]
|
||||
if pkt_id not in B2C_UPDATE_RULES:
|
||||
return frame
|
||||
|
||||
# 用户数据域从 B[120] 开始
|
||||
if len(frame) <= 120:
|
||||
return frame
|
||||
|
||||
user_data = bytearray(frame[120:])
|
||||
rules = B2C_UPDATE_RULES[pkt_id]
|
||||
|
||||
for (code, byte_off, bit_off, bit_len) in rules:
|
||||
val = get_param(code, 0)
|
||||
set_bits(user_data, byte_off, bit_off, bit_len, val)
|
||||
|
||||
# 替换回原帧
|
||||
new_frame = bytearray(frame)
|
||||
new_frame[120:] = user_data
|
||||
# logger.info(f"更新后的B遥测帧:{new_frame}")
|
||||
hex_dump(new_frame, " 更新 B 遥测帧")
|
||||
return bytes(new_frame)
|
||||
|
||||
def loop(self):#2026/4/16新加,不能修复休眠断开重连
|
||||
logger.info(f"✅ B→D/C 遥测转发启动")
|
||||
self.connect_b_telem()
|
||||
self.k6466_send_count = 0
|
||||
|
||||
while True:
|
||||
if not self.b_connected:
|
||||
self.connect_b_telem()
|
||||
time.sleep(0.5)
|
||||
continue
|
||||
|
||||
#sock_b = self.connect_b_telem() #启动2026/4/16
|
||||
try:
|
||||
|
||||
data = self.sock_b.recv(4096)
|
||||
|
||||
# 截取前324个字节 2026/4/20
|
||||
data = data[:324]
|
||||
|
||||
if not data:
|
||||
'''
|
||||
self.not_received_count += 1#注释2026/4/16
|
||||
time.sleep(0.2)
|
||||
'''
|
||||
continue
|
||||
else:
|
||||
self.not_received_count = 0
|
||||
'''
|
||||
if self.not_received_count > 100:
|
||||
logger.error("❌ 没有收到B 遥测,可能断开,重连中...")#注释2026/4/16
|
||||
self.b_connected = False
|
||||
self.sock_b.close()
|
||||
time.sleep(1)
|
||||
continue
|
||||
'''
|
||||
hex_dump(data, "📥 收到 B 遥测帧")
|
||||
|
||||
# 1. 转换后发 D
|
||||
d_data = self.converter.convert(data)
|
||||
if d_data:
|
||||
self.udp_d.sendto(d_data, (self.d_ip, self.d_port))
|
||||
|
||||
# 2. 原样发 C(删除)
|
||||
|
||||
#self.udp_c.sendto(data, (self.c_ip, self.c_port))
|
||||
|
||||
print(f"A2BForward.ck_ab_flag={A2BForward.ck_ab_flag}")
|
||||
|
||||
#2.修改部分遥测量发C 2026/4/18
|
||||
data = self.update_telem_frame(data)
|
||||
|
||||
if A2BForward.ck_ab_flag != False:#c测控AB通道正常的话,向C软件发送遥测
|
||||
self.udp_c.sendto(data, (self.c_ip, self.c_port))
|
||||
|
||||
# 2026/4/30 发给C软件的data同样给G软件发一份
|
||||
self.udp_g.sendto(data, (self.g_ip, self.g_port))
|
||||
|
||||
if A2BForward.ck_c_flag == True:
|
||||
self.k6466_send_count = 0
|
||||
|
||||
if A2BForward.ck_c_flag == False and self.k6466_send_count<6:#如果测控C通道异常,给G软件发送遥控指令。
|
||||
self.udp_g.sendto(cmd_K6466_byte, (self.g_cmd_ip, self.g_cmd_port))
|
||||
time.sleep(0.1)
|
||||
self.udp_e.sendto(cmd_K6466_byte, (self.e_ip, self.e_port))
|
||||
self.k6466_send_count += 1
|
||||
time.sleep(0.1)
|
||||
cmd_K6466_byte_hex= cmd_K6466_byte.hex(" ").upper()
|
||||
logger.info(f"给G软件-BD项目数据中继发送指令K6466出站数据:{cmd_K6466_byte_hex},IP:{self.g_cmd_ip},PORT:{self.g_cmd_port}")
|
||||
logger.info(f"给E软件-专项软件中继发送指令K6466出站数据:{cmd_K6466_byte_hex},IP:{self.e_ip},PORT:{self.e_port}")
|
||||
|
||||
|
||||
# self.udp_g.sendto(cmd_K6466_byte, (self.g_cmd_ip, self.g_cmd_port))
|
||||
# self.k6466_send_count += 1
|
||||
# time.sleep(0.1)
|
||||
# cmd_K6466_byte_hex= cmd_K6466_byte.hex(" ").upper()
|
||||
# logger.info(f"给G软件-BD项目数据中继发送指令K6466出站数据:{cmd_K6466_byte_hex},IP:{self.g_cmd_ip},PORT:{self.g_cmd_port}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ B→D/C 接收异常: {e}")
|
||||
self.b_connected = False #可以先不使用
|
||||
time.sleep(0.1)
|
||||
20
core/global_params.py
Normal file
20
core/global_params.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# 全局遥测参数存储器
|
||||
# 结构:{ "参数代号": 值 }
|
||||
TELEM_PARAMS = {}
|
||||
|
||||
# 分类顺序(你要求的顺序)
|
||||
# 1. 测控
|
||||
# 2. 星间链路终端
|
||||
# 3. SADA
|
||||
# 4. 能源
|
||||
|
||||
def set_param(param_code, value):
|
||||
"""设置参数:代号 + 值"""
|
||||
TELEM_PARAMS[param_code] = value
|
||||
|
||||
def get_param(param_code, default=0):
|
||||
"""获取参数值"""
|
||||
return TELEM_PARAMS.get(param_code, default)
|
||||
|
||||
def clear_params():
|
||||
TELEM_PARAMS.clear()
|
||||
31
core/global_vars.py
Normal file
31
core/global_vars.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# ======================================================
|
||||
# 全局变量:整星安全模式 / 电池电压监测 / 报警状态
|
||||
# ======================================================
|
||||
|
||||
# ---------------------- A 软件遥测全局 ----------------------
|
||||
g_M002YV020 = 0.0 # Vbat1 整组电池电压
|
||||
g_M010YV012 = 0.0 # Vbat2 整组电池电压
|
||||
g_M004YV002 = 0.0
|
||||
g_M004YV004 = 0.0
|
||||
g_M004YV006 = 0.0
|
||||
g_M004YV008 = 0.0
|
||||
g_M004YV010 = 0.0
|
||||
g_M004YV012 = 0.0
|
||||
g_M004YV014 = 0.0
|
||||
g_M004YV016 = 0.0
|
||||
g_M004YV018 = 0.0
|
||||
|
||||
# ---------------------- B 软件阈值全局 ----------------------
|
||||
g_M050YV001 = 30.0 # 下限阈值1 默认29V
|
||||
g_M050YV002 = 29.0 # 下限阈值2 默认29V
|
||||
g_M050YV003 = 25.0 # 下限阈值3 默认29V
|
||||
|
||||
# ---------------------- 报警输出全局 ----------------------
|
||||
g_M050YS055 = 0 # VBOD1 过放电1
|
||||
g_M050YS056 = 0 # VBOD2 过放电2 / 整星安全模式触发
|
||||
g_M050YS057 = 0 # VBOD3 过放电3
|
||||
g_M050YG073 = 0 # 供电模式 0=正常 1=安全模式
|
||||
|
||||
# ---------------------- 连续3次判断计数器 ----------------------
|
||||
g_vbat_check_cnt = 0
|
||||
g_vbat_fail_flag = [False, False, False]
|
||||
287
core/link_manager.py
Normal file
287
core/link_manager.py
Normal file
@@ -0,0 +1,287 @@
|
||||
# import threading
|
||||
# from core.forward_engine import UdpForward, Tcp2UdpForward
|
||||
# from config.settings import LOCAL_PORT, REMOTE
|
||||
|
||||
# # 导入转换器
|
||||
# from converter.b_to_d import B2DConverter
|
||||
# from converter.a_to_b import A2BConverter
|
||||
# from converter.b_to_e import B2EConverter
|
||||
# from converter.a_to_c import A2CConverter
|
||||
|
||||
|
||||
# class LinkManager:
|
||||
# def __init__(self):
|
||||
# self.links = []
|
||||
|
||||
# def register_all(self):
|
||||
# # B→D
|
||||
# self.links.append(
|
||||
# Tcp2UdpForward(
|
||||
# remote_tcp_ip=REMOTE["B"]["ip"],
|
||||
# remote_tcp_port=REMOTE["B"]["port"],
|
||||
# udp_ip=REMOTE["D"]["ip"],
|
||||
# udp_port=REMOTE["D"]["port"],
|
||||
# converter=B2DConverter()
|
||||
# )
|
||||
# )
|
||||
|
||||
# # A→B
|
||||
# self.links.append(
|
||||
# UdpForward(
|
||||
# local_port=LOCAL_PORT["A_B"],
|
||||
# remote_ip=REMOTE["B"]["ip"],
|
||||
# remote_port=REMOTE["B"]["port"],
|
||||
# converter=A2BConverter()
|
||||
# )
|
||||
# )
|
||||
|
||||
# # A→C
|
||||
# self.links.append(
|
||||
# UdpForward(LOCAL_PORT["A_C"], REMOTE["C"]["ip"], REMOTE["C"]["port"], A2CConverter())
|
||||
# )
|
||||
|
||||
# # B→E
|
||||
# self.links.append(
|
||||
# UdpForward(LOCAL_PORT["B_E"], REMOTE["E"]["ip"], REMOTE["E"]["port"], B2EConverter())
|
||||
# )
|
||||
|
||||
# def start(self):
|
||||
# for link in self.links:
|
||||
# threading.Thread(target=link.loop, daemon=True).start()
|
||||
|
||||
import threading
|
||||
from core.forward_engine import UdpForward, Tcp2UdpForward
|
||||
from config.settings import LOCAL_PORT, REMOTE
|
||||
from config_loader import cfg
|
||||
|
||||
from converter.b_to_d import B2DConverter
|
||||
from converter.a_to_b import A2BConverter
|
||||
from converter.b_to_e import B2EConverter
|
||||
from converter.a_to_c import A2CConverter
|
||||
|
||||
# ==================== 新增导入 ====================
|
||||
from converter.c_to_b import C2BConverter
|
||||
from converter.c_to_a import C2AConverter
|
||||
from core.single_to_dual import SingleToDualForward
|
||||
from core.tcp_single_to_dual import TcpSingleToDualForward
|
||||
#from core.a_to_b_forward import A2BForward
|
||||
from core.a2b_forward import A2BForward
|
||||
#from core.udp_c_remote import UdpRemoteC
|
||||
from core.udp_c_remote import UdpCRemote
|
||||
from core.f_to_a_forward import FToAForward # 新增导入
|
||||
|
||||
class LinkManager:
|
||||
def __init__(self):
|
||||
self.links = []
|
||||
|
||||
def register_all(self):
|
||||
# # B→D
|
||||
# self.links.append(
|
||||
# Tcp2UdpForward(
|
||||
# remote_tcp_ip=REMOTE["B"]["ip"],
|
||||
# remote_tcp_port=REMOTE["B"]["port"],
|
||||
# udp_ip=REMOTE["D"]["ip"],
|
||||
# udp_port=REMOTE["D"]["port"],
|
||||
# converter=B2DConverter()
|
||||
# )
|
||||
# )
|
||||
# B → D(转换) + B → C(无条件转发)2026/4/2 B软件换双端TC,TM后停用
|
||||
# self.links.append(Tcp2UdpForward(
|
||||
# remote_tcp_ip=REMOTE["B"]["ip"], remote_tcp_port=REMOTE["B"]["port"],
|
||||
# udp_ip=REMOTE["D"]["ip"], udp_port=REMOTE["D"]["port"],
|
||||
# converter=B2DConverter(),
|
||||
# # 👇 新增:同时转发给 C
|
||||
# forward_c_ip=REMOTE["C"]["ip"],
|
||||
# forward_c_port=REMOTE["C"]["port"]
|
||||
# ))
|
||||
|
||||
# ========== 1. B 遥测 3078 → D + C ==========2026/4/2更新 B软件换双端TC,TM
|
||||
# self.links.append(Tcp2UdpForward(
|
||||
# b_ip=REMOTE["B"]["ip"],
|
||||
# b_telem_port=REMOTE["B"]["port_telem"], # 3078
|
||||
# udp_d_ip=REMOTE["D"]["ip"],
|
||||
# udp_d_port=REMOTE["D"]["port"],
|
||||
# converter=B2DConverter(),
|
||||
# c_ip=REMOTE["C"]["ip"],
|
||||
# c_port=REMOTE["C"]["port"]
|
||||
# ))
|
||||
self.links.append(Tcp2UdpForward(
|
||||
# 2026/4/7更新 使用config.ini配置文件
|
||||
b_ip=cfg.get("REMOTE", "B_IP"),
|
||||
b_telem_port=cfg.get_int("REMOTE", "B_TELEM_PORT"), # 3078
|
||||
udp_d_ip=cfg.get("REMOTE", "D_IP"),
|
||||
udp_d_port=cfg.get_int("REMOTE", "D_PORT"),
|
||||
converter=B2DConverter(),
|
||||
c_ip=cfg.get("REMOTE", "C_IP"),
|
||||
c_port=cfg.get_int("REMOTE", "C_PORT"),
|
||||
#2026/4/30新增G软件-数字卫星C通道遥测,遥控转发
|
||||
g_ip = cfg.get("REMOTE", "B2G_IP"),
|
||||
g_port = cfg.get_int("REMOTE", "B2G_PORT"),
|
||||
g_cmd_ip = cfg.get("REMOTE", "G_CMD_IP"),
|
||||
g_cmd_port = cfg.get_int("REMOTE", "G_CMD_PORT"),
|
||||
#2026/5/11 新增E软件,遥控转发
|
||||
e_ip = cfg.get("REMOTE", "E_IP"),
|
||||
e_port = cfg.get_int("REMOTE", "E_PORT"),
|
||||
))
|
||||
|
||||
# A→B 2026/4/2停用
|
||||
# self.links.append(
|
||||
# UdpForward(
|
||||
# local_port=LOCAL_PORT["A_B"],
|
||||
# remote_ip=REMOTE["B"]["ip"],
|
||||
# remote_port=REMOTE["B"]["port_remote"], ### 暂时是遥控接口,以后要改
|
||||
# converter=A2BConverter()
|
||||
# )
|
||||
# )
|
||||
|
||||
# A→C
|
||||
self.links.append(
|
||||
#UdpForward(LOCAL_PORT["A_C"], REMOTE["C"]["ip"], REMOTE["C"]["port"], A2CConverter())
|
||||
UdpForward(cfg.get_int("LOCAL","A_C"), cfg.get("REMOTE","C_IP"), cfg.get_int("REMOTE","C_PORT"), A2CConverter())#2026/4/7更新 使用config.ini配置文件
|
||||
)
|
||||
|
||||
# B→E
|
||||
self.links.append(
|
||||
#UdpForward(LOCAL_PORT["B_E"], REMOTE["E"]["ip"], REMOTE["E"]["port"], B2EConverter())
|
||||
UdpForward(cfg.get_int("LOCAL","B_E"),cfg.get("REMOTE","E_IP"), cfg.get_int("REMOTE","E_PORT"), B2EConverter())#2026/4/7更新 使用config.ini配置文件
|
||||
)
|
||||
|
||||
# # ==================== 新增两条链路 ====================
|
||||
# # C → B 透传
|
||||
# self.links.append(
|
||||
# UdpForward(
|
||||
# local_port=LOCAL_PORT["C_B"],
|
||||
# remote_ip=REMOTE["B"]["ip"],
|
||||
# remote_port=REMOTE["B"]["port"],
|
||||
# converter=C2BConverter()
|
||||
# )
|
||||
# )
|
||||
|
||||
# # C → A 转发
|
||||
# self.links.append(
|
||||
# UdpForward(
|
||||
# local_port=LOCAL_PORT["C_A"],
|
||||
# remote_ip=REMOTE["A"]["ip"],
|
||||
# remote_port=REMOTE["A"]["port"],
|
||||
# converter=C2AConverter()
|
||||
# )
|
||||
# )
|
||||
# ===================== 核心修改 =====================
|
||||
# # C 单端口 → 同时发给 B 和 A
|
||||
# self.links.append(SingleToDualForward(
|
||||
# local_port=LOCAL_PORT["C"],
|
||||
# # 发给 B
|
||||
# tcp_target_ip=REMOTE["B"]["ip"],
|
||||
# tcp_target_port=REMOTE["B"]["port"],
|
||||
# converter_tcp=C2BConverter(),
|
||||
# # 发给 A
|
||||
# udp_target_ip=REMOTE["A"]["ip"],
|
||||
# udp_target_port=REMOTE["A"]["port"],
|
||||
# converter_udp=C2AConverter()
|
||||
# ))
|
||||
# ===================== 【C 改为 TCP】 2026/3/31停用=====================
|
||||
# self.links.append(TcpSingleToDualForward(
|
||||
# local_port=LOCAL_PORT["C"],
|
||||
# # 转发 B
|
||||
# tcp_target_ip=REMOTE["B"]["ip"],
|
||||
# tcp_target_port=REMOTE["B"]["port"],
|
||||
# converter_tcp=C2BConverter(),
|
||||
# # 转发 A
|
||||
# udp_target_ip=REMOTE["A"]["ip"],
|
||||
# udp_target_port=REMOTE["A"]["port"],
|
||||
# converter_udp=C2AConverter()
|
||||
# ))
|
||||
|
||||
# # 在 register_all 中添加:
|
||||
# self.links.append(
|
||||
# A2BForward(
|
||||
# local_port=LOCAL_PORT["A_LISTEN"],
|
||||
# tcp_target_ip=REMOTE["B"]["ip"],
|
||||
# tcp_target_port=REMOTE["B"]["port"]
|
||||
# )
|
||||
# )
|
||||
|
||||
'''
|
||||
# 在 register_all 末尾加,A-B?
|
||||
self.links.append(
|
||||
A2BForward(
|
||||
#local_port=7100,
|
||||
local_port=LOCAL_PORT["A_B"], #2026/4/2改
|
||||
tcp_ip=REMOTE["B"]["ip"],
|
||||
#tcp_port=REMOTE["B"]["port"]
|
||||
tcp_port=REMOTE["B"]["port_remote"] ##2026/4/2暂时改为遥控接口,以后要改
|
||||
)
|
||||
)
|
||||
'''
|
||||
# A-B 2026/4/3
|
||||
self.links.append(
|
||||
A2BForward(
|
||||
#local_port=LOCAL_PORT["A_B"], #REMOTE["A"]["port"], #2026/4/3改
|
||||
local_port=cfg.get_int("LOCAL", "A_B"),
|
||||
#b_ip=REMOTE["B"]["ip"],
|
||||
b_ip=cfg.get("REMOTE", "B_IP"),#2026/4/7
|
||||
#b_udp_port=REMOTE["B"]["port_udp"] # B UDP 端口
|
||||
b_udp_port=cfg.get_int("REMOTE", "B_UDP_PORT")#2026/4/7
|
||||
)
|
||||
)
|
||||
|
||||
# ===================== C(UDP)遥控 → A + B =====================2026/4/2停用 B软件换双端TC,TM
|
||||
# self.links.append(
|
||||
# UdpRemoteC(
|
||||
# local_port=6004, # C 发指令的 UDP 目标端口
|
||||
# a_ip=REMOTE["A"]["ip"],
|
||||
# a_port=REMOTE["A"]["port"],
|
||||
# b_ip=REMOTE["B"]["ip"],
|
||||
# b_port=REMOTE["B"]["port"],
|
||||
# converter=C2AConverter() # 你原有遥控指令转换器
|
||||
# )
|
||||
# )
|
||||
|
||||
# ========== 2. C UDP 遥控 → A + B 3028 ========== 2026/4/2更新 B软件换双端TC,TM
|
||||
self.links.append(
|
||||
#UdpRemoteC(
|
||||
UdpCRemote(
|
||||
# local_udp_port=6004,
|
||||
# a_ip=REMOTE["A"]["ip"],
|
||||
# a_port=REMOTE["A"]["port"],
|
||||
# b_ip=REMOTE["B"]["ip"],
|
||||
# b_remote_port=REMOTE["B"]["port_remote"], # 3028
|
||||
|
||||
#local_udp_port=cfg.get_int("LOCAL", "C_AB"),#2026/4/7,
|
||||
local_port=cfg.get_int("LOCAL", "C_AB"),#2026/4/7,
|
||||
a_ip=cfg.get("REMOTE", "A_IP"),
|
||||
a_port=cfg.get_int("REMOTE", "A_PORT"),
|
||||
b_ip=cfg.get("REMOTE", "B_IP"),
|
||||
b_remote_port=cfg.get_int("REMOTE", "B_REMOTE_PORT"), # 3028
|
||||
b_gis_port = cfg.get_int("REMOTE","B_DICE_PORT"), # 2026/4/11新增
|
||||
converter=C2AConverter(),
|
||||
#2026/4//30新增E专项,G测控C通道软件转发
|
||||
e_ip=cfg.get("REMOTE", "E_IP"),
|
||||
e_port=cfg.get_int("REMOTE", "E_PORT"),
|
||||
g_ip=cfg.get("REMOTE", "G_CMD_IP"),
|
||||
g_port=cfg.get_int("REMOTE", "G_CMD_PORT")
|
||||
|
||||
))
|
||||
|
||||
|
||||
|
||||
# ========== F → A 转发 新增 ==========2026/4/11废弃
|
||||
# self.links.append(
|
||||
# FToAForward(
|
||||
# local_port=cfg.get_int("LOCAL", "UDP_F_LISTEN_PORT"),
|
||||
# a_ip=cfg.get("REMOTE", "A_IP"),
|
||||
# a_port=cfg.get_int("REMOTE", "A_PORT")
|
||||
# )
|
||||
# )
|
||||
self.links.append(#7786
|
||||
FToAForward(
|
||||
f_ip=cfg.get("REMOTE", "F_IP"),
|
||||
f_port=cfg.get_int("REMOTE", "F_PORT"),
|
||||
a_ip=cfg.get("REMOTE", "A_IP"),
|
||||
a_port=cfg.get_int("REMOTE", "A_FROM_B_PORT")
|
||||
)
|
||||
)
|
||||
|
||||
def start(self):
|
||||
for link in self.links:
|
||||
threading.Thread(target=link.loop, daemon=True).start()
|
||||
64
core/single_to_dual.py
Normal file
64
core/single_to_dual.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import socket
|
||||
import threading
|
||||
from utils.logger import logger
|
||||
from utils.hex_helper import hex_dump
|
||||
|
||||
class SingleToDualForward:
|
||||
"""
|
||||
单端口接收,同时发给两个目标:
|
||||
1) 转发给 TCP 目标(B)
|
||||
2) 同时转发给 UDP 目标(A,条件转发)
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
local_port,
|
||||
tcp_target_ip, tcp_target_port, converter_tcp,
|
||||
udp_target_ip, udp_target_port, converter_udp
|
||||
):
|
||||
self.local_port = local_port
|
||||
self.tcp_ip = tcp_target_ip
|
||||
self.tcp_port = tcp_target_port
|
||||
self.converter_tcp = converter_tcp # C→B
|
||||
|
||||
self.udp_ip = udp_target_ip
|
||||
self.udp_port = udp_target_port
|
||||
self.converter_udp = converter_udp # C→A
|
||||
|
||||
self.tcp_sock = None
|
||||
self.udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
def connect_tcp(self):
|
||||
while True:
|
||||
try:
|
||||
self.tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.tcp_sock.connect((self.tcp_ip, self.tcp_port))
|
||||
logger.info(f"✅ TCP 连接 B 成功 {self.tcp_ip}:{self.tcp_port}")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"❌ TCP 连接失败,重试: {e}")
|
||||
threading.Event().wait(2)
|
||||
|
||||
def loop(self):
|
||||
# 绑定单端口接收 C
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind(("0.0.0.0", self.local_port))
|
||||
logger.info(f"✅ C 单端口监听启动: 0.0.0.0:{self.local_port}")
|
||||
|
||||
self.connect_tcp()
|
||||
|
||||
while True:
|
||||
data, addr = sock.recvfrom(4096)
|
||||
hex_dump(data, f"收到 C 指令 {addr}")
|
||||
|
||||
# ========== 1. 转发给 B(无条件) ==========
|
||||
try:
|
||||
b_data = self.converter_tcp.convert(data)
|
||||
if b_data:
|
||||
self.tcp_sock.send(b_data)
|
||||
except:
|
||||
self.connect_tcp()
|
||||
|
||||
# ========== 2. 转发给 A(条件判断) ==========
|
||||
a_data = self.converter_udp.convert(data)
|
||||
if a_data:
|
||||
self.udp_sock.sendto(a_data, (self.udp_ip, self.udp_port))
|
||||
45
core/tcp_forward_client.py
Normal file
45
core/tcp_forward_client.py
Normal file
@@ -0,0 +1,45 @@
|
||||
"""
|
||||
2026/3/31
|
||||
Tan Mingyan
|
||||
2026/3/31/, 软件C使用UDP协议,不再需要这个类
|
||||
"""
|
||||
import socket
|
||||
import threading
|
||||
from utils.hex_helper import hex_dump
|
||||
from utils.logger import logger
|
||||
|
||||
class TcpForwardClient:
|
||||
"""
|
||||
专门用于:无条件原样转发 TCP 数据(发给 C 软件)
|
||||
"""
|
||||
def __init__(self, target_ip, target_port):
|
||||
self.ip = target_ip
|
||||
self.port = target_port
|
||||
self.sock = None
|
||||
self.lock = threading.Lock()
|
||||
|
||||
def connect(self):
|
||||
while True:
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((self.ip, self.port))
|
||||
with self.lock:
|
||||
self.sock = s
|
||||
logger.info(f"✅ C软件转发连接成功: {self.ip}:{self.port}")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"❌ C软件转发连接失败,重连中: {e}")
|
||||
threading.Event().wait(2)
|
||||
|
||||
def send(self, data):
|
||||
"""原样转发,不修改任何数据"""
|
||||
try:
|
||||
with self.lock:
|
||||
if self.sock:
|
||||
self.sock.send(data)
|
||||
#logger.info(f"✅ C软件转发成功: {self.ip}:{self.port}")
|
||||
hex_dump(data,"B-C透明转发遥测帧")
|
||||
return True
|
||||
except:
|
||||
self.connect()
|
||||
return False
|
||||
83
core/tcp_single_to_dual.py
Normal file
83
core/tcp_single_to_dual.py
Normal file
@@ -0,0 +1,83 @@
|
||||
import socket
|
||||
import threading
|
||||
from utils.logger import logger
|
||||
from utils.hex_helper import hex_dump
|
||||
|
||||
class TcpSingleToDualForward:
|
||||
"""
|
||||
C 软件:TCP 客户端
|
||||
M 软件:TCP 服务端(单端口监听)
|
||||
收到数据后:
|
||||
1) 转发给 B(TCP)
|
||||
2) 条件转发给 A(UDP)
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
local_port,
|
||||
tcp_target_ip, tcp_target_port, converter_tcp,
|
||||
udp_target_ip, udp_target_port, converter_udp
|
||||
):
|
||||
self.local_port = local_port
|
||||
self.tcp_ip = tcp_target_ip
|
||||
self.tcp_port = tcp_target_port
|
||||
self.converter_tcp = converter_tcp # C→B
|
||||
|
||||
self.udp_ip = udp_target_ip
|
||||
self.udp_port = udp_target_port
|
||||
self.converter_udp = converter_udp # C→A
|
||||
|
||||
self.tcp_sock = None # 发给 B 的连接
|
||||
self.udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
def connect_tcp_b(self):
|
||||
while True:
|
||||
try:
|
||||
self.tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.tcp_sock.connect((self.tcp_ip, self.tcp_port))
|
||||
logger.info(f"✅ 已连接 B 软件 {self.tcp_ip}:{self.tcp_port}")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 连接 B 失败,重连中: {e}")
|
||||
threading.Event().wait(2)
|
||||
|
||||
def handle_client(self, client_socket):
|
||||
self.connect_tcp_b()
|
||||
while True:
|
||||
try:
|
||||
data = client_socket.recv(4096)
|
||||
if not data:
|
||||
logger.warning("⚠️ C 软件断开连接")
|
||||
break
|
||||
|
||||
hex_dump(data, "收到 C 软件指令")
|
||||
|
||||
# ========== 1. 转发 B ==========
|
||||
try:
|
||||
b_data = self.converter_tcp.convert(data)
|
||||
if b_data:
|
||||
self.tcp_sock.send(b_data)
|
||||
except:
|
||||
self.connect_tcp_b()
|
||||
|
||||
# ========== 2. 转发 A ==========
|
||||
a_data = self.converter_udp.convert(data)
|
||||
if a_data:
|
||||
self.udp_sock.sendto(a_data, (self.udp_ip, self.udp_port))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"客户端异常: {e}")
|
||||
break
|
||||
|
||||
client_socket.close()
|
||||
|
||||
def loop(self):
|
||||
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
server_sock.bind(("0.0.0.0", self.local_port))
|
||||
server_sock.listen(5)
|
||||
logger.info(f"✅ TCP 监听 C 软件: 0.0.0.0:{self.local_port}")
|
||||
|
||||
while True:
|
||||
client_sock, addr = server_sock.accept()
|
||||
logger.info(f"✅ C 软件已连接: {addr}")
|
||||
threading.Thread(target=self.handle_client, args=(client_sock,), daemon=True).start()
|
||||
369
core/udp_c_remote.py
Normal file
369
core/udp_c_remote.py
Normal file
@@ -0,0 +1,369 @@
|
||||
# import socket
|
||||
# import threading
|
||||
# from utils.logger import logger
|
||||
# from utils.hex_helper import hex_dump
|
||||
|
||||
# class UdpRemoteC:#2026/4/2停用,因为B软件用双端口TCP,遥控端口3028
|
||||
# """
|
||||
# C 软件(UDP)发遥控指令 → M 接收 → 转发 A(UDP) + B(TCP)
|
||||
# """
|
||||
# def __init__(self, local_port, a_ip, a_port, b_ip, b_port, converter):
|
||||
# self.local_port = local_port
|
||||
# self.a_ip = a_ip
|
||||
# self.a_port = a_port
|
||||
# self.b_ip = b_ip
|
||||
# self.b_port = b_port
|
||||
# self.converter = converter
|
||||
|
||||
# # A:UDP
|
||||
# self.udp_a = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# # B:TCP(长连接)
|
||||
# self.tcp_b = None
|
||||
# self.lock = threading.Lock()
|
||||
|
||||
# def connect_b(self):
|
||||
# """B TCP 重连"""
|
||||
# while True:
|
||||
# try:
|
||||
# s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# s.connect((self.b_ip, self.b_port))
|
||||
# with self.lock:
|
||||
# self.tcp_b = s
|
||||
# logger.info(f"✅ 遥控-B TCP 连接成功: {self.b_ip}:{self.b_port}")
|
||||
# return
|
||||
# except Exception as e:
|
||||
# logger.error("❌ 遥控-B 连接失败,重连中...")
|
||||
# threading.Event().wait(2)
|
||||
|
||||
# def loop(self):
|
||||
# # 监听 C UDP
|
||||
# sock_c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# #sock_c.bind(("0.0.0.0", self.local_port))
|
||||
# sock_c.bind(("127.0.0.1", self.local_port))
|
||||
# logger.info(f"✅ 监听 C 遥控 UDP: {self.local_port}")
|
||||
|
||||
# # 连接 B
|
||||
# self.connect_b()
|
||||
|
||||
# while True:
|
||||
# data, addr = sock_c.recvfrom(4096)
|
||||
# if not data:
|
||||
# continue
|
||||
|
||||
# hex_dump(data, "📥 收到 C 遥控指令")
|
||||
|
||||
# # 1. 转换格式(你原有 C→A 转换器)
|
||||
# a_frame = self.converter.convert(data)
|
||||
# if not a_frame:
|
||||
# a_frame = data
|
||||
|
||||
# # 2. 转发 A(UDP)
|
||||
# self.udp_a.sendto(a_frame, (self.a_ip, self.a_port))
|
||||
# logger.info("📤 已发往 A")
|
||||
|
||||
# # 3. 转发 B(TCP)
|
||||
# try:
|
||||
# with self.lock:
|
||||
# if self.tcp_b:
|
||||
# self.tcp_b.send(data)
|
||||
# logger.info("📤 已发往 B")
|
||||
# except:
|
||||
# self.connect_b()
|
||||
# try:
|
||||
# with self.lock:
|
||||
# self.tcp_b.send(data)
|
||||
# except:
|
||||
# pass
|
||||
|
||||
# import socket
|
||||
# import threading
|
||||
# from utils.logger import logger
|
||||
# from utils.hex_helper import hex_dump
|
||||
# from core.b_gis_client import BGisClient # 新增
|
||||
|
||||
# class UdpRemoteC: #2026/4/11停用
|
||||
# """
|
||||
# C(UDP 6004) 遥控指令 → M → 转发 A(UDP) + B(3028 TCP Server)
|
||||
# """
|
||||
# def __init__(self, local_udp_port, a_ip, a_port, b_ip, b_remote_port,b_gis_port, converter):
|
||||
# self.local_port = local_udp_port # 6004
|
||||
# self.a_ip = a_ip
|
||||
# self.a_port = a_port
|
||||
# self.b_ip = b_ip
|
||||
# self.b_remote_port = b_remote_port # 3028
|
||||
# self.converter = converter
|
||||
# self.b_gis_port = b_gis_port # 新增
|
||||
|
||||
# self.udp_a = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# self.tcp_b = None
|
||||
# self.lock = threading.Lock()
|
||||
|
||||
# # 新增 B 地测客户端2026/4/11
|
||||
# self.b_gis = BGisClient(self.b_ip, self.b_gis_port)
|
||||
|
||||
# def connect_b_remote(self):
|
||||
# """连接 B 遥控 TCP Server 3028"""
|
||||
# while True:
|
||||
# try:
|
||||
# s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# logger.info(f"B 遥控端口{self.b_ip}, {self.b_remote_port}")
|
||||
# s.connect((self.b_ip, self.b_remote_port))
|
||||
# with self.lock:
|
||||
# self.tcp_b = s
|
||||
|
||||
# logger.info(f"✅ 已连接 B 遥控端口 3028")
|
||||
# return
|
||||
# except Exception as e:
|
||||
# logger.error("❌ 连接 B 3028 失败,重试中...")
|
||||
# threading.Event().wait(2)
|
||||
|
||||
# def loop(self):
|
||||
# # 绑定 UDP 监听 C
|
||||
# sock_c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# sock_c.bind(("0.0.0.0", self.local_port))
|
||||
# logger.info(f"✅ UDP 监听 C 遥控端口: {self.local_port}")
|
||||
|
||||
# # 连接 B 遥控
|
||||
# self.connect_b_remote()
|
||||
|
||||
# while True:
|
||||
# data, addr = sock_c.recvfrom(4096)
|
||||
# if not data:
|
||||
# continue
|
||||
|
||||
# hex_dump(data, "📥 收到 C 遥控指令")
|
||||
|
||||
# # 转发 A
|
||||
# a_frame = self.converter.convert(data)
|
||||
# if a_frame:
|
||||
# self.udp_a.sendto(a_frame, (self.a_ip, self.a_port))
|
||||
# logger.info("C遥控指令已发往 B")
|
||||
|
||||
# # 转发 B 3028
|
||||
# try:
|
||||
# with self.lock:
|
||||
# self.tcp_b.send(data)
|
||||
# self.b_gis.send(data) # 新增:无条件转发给 B 地测端口
|
||||
# except:
|
||||
# self.connect_b_remote()
|
||||
# try:
|
||||
# with self.lock:
|
||||
# self.tcp_b.send(data)
|
||||
# except:
|
||||
# pass
|
||||
|
||||
# import socket
|
||||
# import threading
|
||||
# import time
|
||||
# from core.b_gis_client import BGisClient
|
||||
# from utils.logger import logger
|
||||
# from config_loader import cfg
|
||||
|
||||
# class UdpCRemote:
|
||||
# def __init__(self, local_port, a_ip, a_port, b_ip, b_remote_port, b_gis_port, converter):
|
||||
# self.local_port = local_port
|
||||
# self.a_ip = a_ip
|
||||
# self.a_port = a_port
|
||||
# self.b_ip = b_ip
|
||||
# self.b_remote_port = b_remote_port
|
||||
# self.b_gis_port = b_gis_port # 新增
|
||||
# self.converter = converter
|
||||
|
||||
# # 初始化B地测客户端
|
||||
# self.b_gis = BGisClient(self.b_ip, self.b_gis_port)
|
||||
|
||||
# self.sock_c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# self.sock_c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
# self.sock_a = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# self.sock_b = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
# self.b_connected = False
|
||||
|
||||
# def connect_b(self):
|
||||
# while True:
|
||||
# try:
|
||||
# self.sock_b.connect((self.b_ip, self.b_remote_port))
|
||||
# self.b_connected = True
|
||||
# logger.info(f"✅ 连接 B 遥控端口成功:{self.b_ip}:{self.b_remote_port}")
|
||||
# return
|
||||
# except Exception as e:
|
||||
# logger.error(f"❌ 连接 B 遥控端口失败,重试:{e}")
|
||||
# time.sleep(1)
|
||||
|
||||
# def loop(self):
|
||||
# try:
|
||||
# self.sock_c.bind(("0.0.0.0", self.local_port))
|
||||
# logger.info(f"✅ C 遥控监听:UDP {self.local_port}")
|
||||
# except Exception as e:
|
||||
# logger.error(f"❌ C 监听失败:{e}")
|
||||
# return
|
||||
|
||||
# self.connect_b()
|
||||
|
||||
# while True:
|
||||
# data, addr = self.sock_c.recvfrom(8192)
|
||||
# if not data:
|
||||
# continue
|
||||
|
||||
# try:
|
||||
# forward_data = self.converter.convert(data)
|
||||
# logger.info(f"📤 C→B 指令转发:{forward_data.hex()}")
|
||||
|
||||
# # 发送给原有 B 端口
|
||||
# if self.b_connected:
|
||||
# self.sock_b.send(forward_data)
|
||||
|
||||
# # ===================== 新增:无条件转发给 B 地测 4028 =====================
|
||||
# self.b_gis.send(forward_data)
|
||||
|
||||
# # 发送给 A
|
||||
# self.sock_a.sendto(forward_data, (self.a_ip, self.a_port))
|
||||
|
||||
# except Exception as e:
|
||||
# logger.error(f"❌ C 指令转发异常:{e}")
|
||||
|
||||
import socket
|
||||
import time
|
||||
from utils.logger import logger
|
||||
|
||||
special_cmd_list={#分别是K6794 专项星间实时遥测发送使能-271,K6794 专项星间实时遥测发送使能-271,K6795专项星间实时遥测发送禁止-271,K6465入站-271,K6466 出站-271
|
||||
b"EB9001073500EB90B571A50911C00100E505F4ED4500000000000000000000000000000000000000000000000000000000DDAAAAAAAA88880C1B0C02023366A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5CCCCCCCCCCCCCCCC7FCEA5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5DF0B91225716",
|
||||
b"EB9001073500EB90B571A50911C00100E505F4ED4500000000000000000000000000000000000000000000000000000000DDAAAAAAAA88880C1B0C02024477A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5CCCCCCCCCCCCCCCCB2EBA5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5DF0B91945716",
|
||||
b"EB9001073500EB90B571A50911C00100E505F4ED4500000000000000000000000000000000000000000000000000000000DDAAAAAAAA88880C1B0C020233AAA5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5CCCCCCCCCCCCCCCCF26EA5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5DF0B91795716",
|
||||
b"EB9001073500EB90B571A50911C00100E505F4ED4500000000000000000000000000000000000000000000000000000000DDAAAAAAAA88880C1B0C020233BBA5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5CCCCCCCCCCCCCCCCECB6A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5DF0B91CC5716"
|
||||
}
|
||||
class UdpCRemote:
|
||||
def __init__(self, local_port, a_ip, a_port, b_ip, b_remote_port, b_gis_port, converter, e_ip, e_port, g_ip, g_port):
|
||||
self.local_port = local_port
|
||||
self.a_ip = a_ip
|
||||
self.a_port = a_port
|
||||
self.b_ip = b_ip
|
||||
self.b_remote_port = b_remote_port
|
||||
self.b_gis_port = b_gis_port # 地测端口 4028
|
||||
##2026/4/30 部分特殊指令转发
|
||||
self.e_ip = e_ip
|
||||
self.e_port = e_port
|
||||
self.g_ip = g_ip
|
||||
self.g_port = g_port
|
||||
|
||||
self.converter = converter
|
||||
|
||||
# C 指令监听(UDP)
|
||||
self.sock_c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.sock_c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
# 发给 A(UDP)
|
||||
self.sock_a = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
# 发给 B 原遥控端口 TCP(3028)
|
||||
self.sock_b = None
|
||||
self.b_connected = False
|
||||
|
||||
# 发给 B 地测端口 TCP(4028)—— 这里是你要的新增!
|
||||
self.sock_b_gis = None
|
||||
self.b_gis_connected = False
|
||||
|
||||
#发给E专项
|
||||
self.udp_e = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
#发给G
|
||||
self.udp_g = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
# 连接 B 原遥控端口 3028
|
||||
def connect_b_remote(self):
|
||||
while True:
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(3)
|
||||
s.connect((self.b_ip, self.b_remote_port))
|
||||
self.sock_b = s
|
||||
self.b_connected = True
|
||||
logger.info(f"✅ 连接 B 遥控端口成功:{self.b_remote_port}")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"❌ B 遥控端口连接失败,重试:{e}")
|
||||
time.sleep(1)
|
||||
|
||||
# 连接 B 地测端口 4028 —— 完整实现!
|
||||
def connect_b_gis(self):
|
||||
while True:
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(3)
|
||||
s.connect((self.b_ip, self.b_gis_port))
|
||||
self.sock_b_gis = s
|
||||
self.b_gis_connected = True
|
||||
logger.info(f"✅ 连接 B 地测端口成功:{self.b_gis_port}")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"❌ B 地测端口连接失败,重试:{e}")
|
||||
time.sleep(1)
|
||||
|
||||
def loop(self):
|
||||
try:
|
||||
self.sock_c.bind(("0.0.0.0", self.local_port))
|
||||
logger.info(f"✅ C 指令监听:{self.local_port}")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ C 监听失败:{e}")
|
||||
return
|
||||
|
||||
# 启动时同时连接两个端口
|
||||
self.connect_b_remote()
|
||||
time.sleep(0.01)
|
||||
self.connect_b_gis()
|
||||
|
||||
while True:
|
||||
data, addr = self.sock_c.recvfrom(8192)
|
||||
if not data:
|
||||
continue
|
||||
|
||||
try:
|
||||
# 转换指令
|
||||
forward_data = self.converter.convert(data)
|
||||
#logger.info(f"📤 转发C指令:{forward_data.hex()}")
|
||||
|
||||
# 1. 转发 A(UDP)
|
||||
if forward_data is not None:
|
||||
self.sock_a.sendto(forward_data, (self.a_ip, self.a_port))
|
||||
|
||||
# 2. 转发 B 遥控端口(TCP)
|
||||
if self.b_connected:
|
||||
try:
|
||||
self.sock_b.sendall(data)
|
||||
except:
|
||||
self.b_connected = False
|
||||
|
||||
# 3. 转发 B 地测端口(TCP)—— 无条件转发!
|
||||
if self.b_gis_connected:
|
||||
try:
|
||||
self.sock_b_gis.sendall(data)
|
||||
logger.info(f"📤 转发C指令到B地测端口:{data.hex()}")
|
||||
except:
|
||||
self.b_gis_connected = False
|
||||
|
||||
## 判断指令是否是K6465,K6466,K6794,K6795,是就转发给D和G软件
|
||||
# 转换为小写的十六进制字节串进行比较
|
||||
data_hex_lower = data.hex().lower().encode()
|
||||
|
||||
# 判断是否在列表中(列表中的命令也预先转为小写)
|
||||
special_cmd_lower = {cmd.lower() for cmd in special_cmd_list}
|
||||
|
||||
if data_hex_lower in special_cmd_lower:
|
||||
#print("匹配成功")
|
||||
#if data in special_cmd_list:
|
||||
# 转发E专项软件UDP
|
||||
self.udp_e.sendto(data, (self.e_ip, self.e_port))
|
||||
|
||||
#转发G软件,测控C通道,UDP
|
||||
self.udp_g.sendto(data, (self.g_ip, self.g_port))
|
||||
logger.info(f"📤 转发C指令到E专项软件,端口{self.e_port},G软件BD项目数据中继,端口{self.g_port}, 指令:{data.hex()}")
|
||||
|
||||
# 自动重连
|
||||
if not self.b_connected:
|
||||
self.connect_b_remote()
|
||||
if not self.b_gis_connected:
|
||||
self.connect_b_gis()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 指令转发异常:{e}")
|
||||
Reference in New Issue
Block a user