271 lines
9.2 KiB
Python
271 lines
9.2 KiB
Python
"""
|
||
模块2:UDP发送响应包模块
|
||
向37001端口发送控制指令的执行结果
|
||
"""
|
||
|
||
import socket
|
||
import logging
|
||
import time
|
||
from typing import Optional, Tuple
|
||
from data_structures import (
|
||
ResponsePacket, ErrorPacket, DeviceStatus,
|
||
CONTROL_TX_PORT, ExecutionStatus, StatusPacketType
|
||
)
|
||
|
||
|
||
class ResponseSender:
|
||
"""响应包发送模块"""
|
||
|
||
def __init__(self, remote_host: str = '127.0.0.1', port: int = CONTROL_TX_PORT, local_ip: Optional[str] = None):
|
||
"""
|
||
初始化响应发送模块
|
||
|
||
Args:
|
||
remote_host: 远程主机地址
|
||
port: 发送端口
|
||
local_ip: 本地绑定IP(用于指定发送源IP)
|
||
"""
|
||
self.remote_host = remote_host
|
||
self.port = port
|
||
self.local_ip = local_ip
|
||
self.socket = None
|
||
|
||
# 配置日志
|
||
self.logger = logging.getLogger(f'Module2-Sender:{port}')
|
||
self.logger.setLevel(logging.INFO)
|
||
if not self.logger.handlers:
|
||
handler = logging.StreamHandler()
|
||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||
handler.setFormatter(formatter)
|
||
self.logger.addHandler(handler)
|
||
|
||
# 创建UDP套接字
|
||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||
if self.local_ip:
|
||
try:
|
||
self.socket.bind((self.local_ip, 0))
|
||
self.logger.info(f"Response sender bound to {self.local_ip}")
|
||
except Exception as e:
|
||
self.logger.error(f"Failed to bind response sender to {self.local_ip}: {e}")
|
||
|
||
def send_response(self, remote_addr: Tuple[str, int],
|
||
status: int = ExecutionStatus.SUCCESS,
|
||
device_status: Optional[DeviceStatus] = None) -> bool:
|
||
"""
|
||
发送控制命令执行结果响应包
|
||
|
||
Args:
|
||
remote_addr: 远程地址 (host, port)
|
||
status: 执行状态 (0=成功, 1=错误)
|
||
device_status: 设备状态(可选)
|
||
|
||
Returns:
|
||
是否发送成功
|
||
"""
|
||
try:
|
||
# 创建错误包
|
||
error_packet = ErrorPacket(
|
||
status_packet_type=StatusPacketType.CONTROL_RESULT,
|
||
execution_status=status
|
||
)
|
||
|
||
# 创建响应包
|
||
# 状态包类型:[0]=错误包(回报), [1]=设备状态
|
||
# 如果是回报则[0]设为1,如果是设备状态则[1]设为1
|
||
response = ResponsePacket(
|
||
status_packet_type=[1, 1], # [0]=1表示错误包有效, [1]=0表示设备状态无效
|
||
device_number=1,
|
||
error_packet=error_packet,
|
||
device_status=device_status if device_status else DeviceStatus()
|
||
)
|
||
|
||
# 序列化为字节流
|
||
data = response.to_bytes()
|
||
|
||
# 发送数据
|
||
self.socket.sendto(data, remote_addr)
|
||
|
||
self.logger.info(f"Response sent to {remote_addr} - Status: {status}")
|
||
self.logger.info(f"DEBUG: Raw packet data ({len(data)} bytes): {data.hex()}")
|
||
#self.logger.debug(f"Packet size: {len(data)} bytes")
|
||
|
||
return True
|
||
|
||
except Exception as e:
|
||
self.logger.error(f"Failed to send response: {e}")
|
||
return False
|
||
|
||
def send_status_packet(self, remote_addr: Tuple[str, int],
|
||
device_status: DeviceStatus) -> bool:
|
||
"""
|
||
发送设备状态包
|
||
|
||
Args:
|
||
remote_addr: 远程地址 (host, port)
|
||
device_status: 设备状态
|
||
|
||
Returns:
|
||
是否发送成功
|
||
"""
|
||
try:
|
||
# 创建错误包(状态设为成功)
|
||
error_packet = ErrorPacket(
|
||
status_packet_type=StatusPacketType.CONTROL_RESULT,
|
||
execution_status=ExecutionStatus.SUCCESS
|
||
)
|
||
|
||
# 创建响应包,包含设备状态
|
||
# 状态包类型:[0]=错误包(回报), [1]=设备状态
|
||
# 如果是回报则[0]设为1,如果是设备状态则[1]设为1
|
||
response = ResponsePacket(
|
||
status_packet_type=[1, 1], # [0]=0表示错误包无效, [1]=1表示设备状态有效
|
||
device_number=1,
|
||
error_packet=error_packet,
|
||
device_status=device_status
|
||
)
|
||
|
||
# 序列化为字节流
|
||
data = response.to_bytes()
|
||
|
||
# 发送数据
|
||
self.socket.sendto(data, remote_addr)
|
||
|
||
self.logger.info(f"Status packet sent to {remote_addr}")
|
||
#self.logger.info(f"Status sent to {remote_addr} - Status: {status}")
|
||
self.logger.info(f"DEBUG: Raw packet data ({len(data)} bytes): {data.hex()}")
|
||
#self.logger.debug(f"Packet size: {len(data)} bytes")
|
||
|
||
return True
|
||
|
||
except Exception as e:
|
||
self.logger.error(f"Failed to send status packet: {e}")
|
||
return False
|
||
|
||
def close(self):
|
||
"""关闭发送模块"""
|
||
if self.socket:
|
||
self.socket.close()
|
||
self.logger.info("Sender closed")
|
||
|
||
|
||
class StatusPacketSender:
|
||
"""定时发送状态包的模块"""
|
||
|
||
def __init__(self, remote_addr: Tuple[str, int], interval: float = 1.0, local_ip: Optional[str] = None):
|
||
"""
|
||
初始化定时状态包发送器
|
||
|
||
Args:
|
||
remote_addr: 远程地址 (host, port)
|
||
interval: 发送间隔(秒)
|
||
local_ip: 本地绑定IP
|
||
"""
|
||
self.remote_addr = remote_addr
|
||
self.interval = interval
|
||
self.local_ip = local_ip
|
||
self.sender = ResponseSender(remote_addr[0], CONTROL_TX_PORT, local_ip=local_ip)
|
||
self.running = False
|
||
self.send_thread = None
|
||
|
||
# 配置日志
|
||
self.logger = logging.getLogger(f'StatusPacketSender:{remote_addr}')
|
||
self.logger.setLevel(logging.INFO)
|
||
if not self.logger.handlers:
|
||
handler = logging.StreamHandler()
|
||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||
handler.setFormatter(formatter)
|
||
self.logger.addHandler(handler)
|
||
|
||
def start(self):
|
||
"""启动定时发送"""
|
||
if self.running:
|
||
self.logger.warning("Status packet sender is already running")
|
||
return
|
||
|
||
self.running = True
|
||
self.logger.info(f"Starting status packet sender for {self.remote_addr}")
|
||
|
||
# 启动发送线程
|
||
import threading
|
||
self.send_thread = threading.Thread(target=self._send_loop, daemon=True)
|
||
self.send_thread.start()
|
||
|
||
def stop(self):
|
||
"""停止定时发送"""
|
||
self.running = False
|
||
if self.send_thread:
|
||
self.send_thread.join(timeout=2)
|
||
self.sender.close()
|
||
self.logger.info("Status packet sender stopped")
|
||
|
||
def _send_loop(self):
|
||
"""发送循环"""
|
||
while self.running:
|
||
try:
|
||
# 创建设备状态
|
||
device_status = DeviceStatus(
|
||
cpu_temp=45,
|
||
ant_temp=40,
|
||
rf_temp=50,
|
||
nvme_temp=35,
|
||
fpga_temp=48,
|
||
sys_voltage=12,
|
||
clock_lock=1,
|
||
imu_state=1,
|
||
mem_volume=8192,
|
||
disk_volume=50,
|
||
north_velocity=10.5,
|
||
sky_velocity=0.5,
|
||
east_velocity=5.2,
|
||
altitude=1000.0,
|
||
longitude=1159154650, # 116.0°
|
||
latitude=403585769, # 40.0°
|
||
angle_roll=0.0,
|
||
angle_yaw=90.0,
|
||
angle_pitch=0.0,
|
||
year_month_day=20260119,
|
||
hour_min_sec=120000,
|
||
antenna_azimuth=0,
|
||
antenna_pitch=0,
|
||
is_boot=1,
|
||
satellite_num=12,
|
||
pos_flag=4,
|
||
orient_flag=1
|
||
)
|
||
|
||
# 发送状态包
|
||
self.sender.send_status_packet(self.remote_addr, device_status)
|
||
|
||
# 等待指定间隔
|
||
time.sleep(self.interval)
|
||
|
||
except Exception as e:
|
||
if self.running:
|
||
self.logger.error(f"Error in send loop: {e}")
|
||
break
|
||
|
||
|
||
if __name__ == '__main__':
|
||
# 配置日志
|
||
logging.basicConfig(level=logging.INFO)
|
||
|
||
# 创建发送模块
|
||
sender = ResponseSender('127.0.0.1', CONTROL_TX_PORT)
|
||
|
||
# 发送响应包
|
||
print("Sending response packet...")
|
||
sender.send_response(('127.0.0.1', 12345), ExecutionStatus.SUCCESS)
|
||
|
||
# 发送设备状态
|
||
device_status = DeviceStatus(
|
||
cpu_temp=45,
|
||
ant_temp=40,
|
||
rf_temp=50,
|
||
is_boot=1,
|
||
satellite_num=12
|
||
)
|
||
print("Sending status packet...")
|
||
sender.send_status_packet(('127.0.0.1', 12345), device_status)
|
||
|
||
sender.close()
|