import os import sys sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) import time import threading import socket import random from pymavlink import mavutil from pymavlink.dialects.v20 import common as mavlink2 from fc_network_adapter.asyncioManager import AsyncIOManager, Connection class MockMAVLinkSocket: """模擬 pymavlink socket 行為的類,用於測試""" def __init__(self, name="mock", simulate_errors=False): self.name = name self.simulate_errors = simulate_errors self.is_closed = False self.received_msgs = [] self.seq = 0 def recv_msg(self): """模擬接收 MAVLink 消息""" if self.is_closed: return None # 隨機模擬網絡延遲 time.sleep(random.uniform(0.01, 0.05)) # 偶爾模擬錯誤 if self.simulate_errors and random.random() < 0.1: raise Exception("Simulated network error") # 70% 的機率返回消息,30% 返回 None (模擬無數據可讀) if random.random() > 0.3: msg = self._generate_mavlink_message() self.received_msgs.append(msg) return msg return None def _generate_mavlink_message(self): """生成模擬 MAVLink 消息""" # 創建 MAVLink 實例 mav = mavlink2.MAVLink(self) # 設置來源系統和組件 mav.srcSystem = random.randint(1, 5) mav.srcComponent = random.randint(1, 5) # 創建 HEARTBEAT 消息 msg = mavlink2.MAVLink_heartbeat_message( type=mavlink2.MAV_TYPE_QUADROTOR, autopilot=mavlink2.MAV_AUTOPILOT_GENERIC, base_mode=0, custom_mode=0, system_status=0, mavlink_version=3 ) # 打包消息 msg.pack(mav) self.seq += 1 return msg def write(self, data): """模擬發送數據""" if self.is_closed: raise Exception("Socket is closed") # 模擬寫入操作 time.sleep(random.uniform(0.001, 0.01)) # 偶爾模擬錯誤 if self.simulate_errors and random.random() < 0.1: raise Exception("Simulated write error") return len(data) def close(self): """關閉連接""" self.is_closed = True def create_mock_mavlink_sockets(count=3): """創建多個模擬 MAVLink socket""" sockets = [] for i in range(count): # 每三個 socket 中有一個模擬錯誤 simulate_errors = (i % 3 == 0) socket = MockMAVLinkSocket(f"mock_{i}", simulate_errors) sockets.append(socket) return sockets def monitor_thread(io_manager): """監視 AsyncIOManager 狀態的執行緒""" print("Starting monitoring thread...") try: while True: # 獲取總體統計資訊 stats = io_manager.get_stats() print(f"\n=== AsyncIOManager Stats ===") print(f"Total connections: {stats.get('connection_count', 0)}") print(f"Total messages received: {stats.get('rx_count', 0)}") print(f"Total bytes received: {stats.get('rx_bytes', 0)}") print(f"Total errors: {stats.get('errors', 0)}") # 獲取每個連接的緩衝區狀態 for socket_id in io_manager.connections: buffer = io_manager.get_buffer(socket_id) conn_stats = io_manager.get_stats(socket_id) if buffer and not io_manager.connections[socket_id].is_closed: print(f"Connection {socket_id}: Buffer size={buffer.size()}, " + f"Messages={conn_stats.get('rx_count', 0)}, " + f"Last activity={time.time() - io_manager.connections[socket_id].last_activity:.1f}s ago") # 每秒更新一次 time.sleep(1.0) except KeyboardInterrupt: print("Monitoring thread stopped.") def consumer_thread(io_manager, socket_id): """從指定連接的緩衝區消費消息""" print(f"Starting consumer for socket {socket_id}...") try: while True: # 獲取緩衝區 buffer = io_manager.get_buffer(socket_id) if not buffer: print(f"Consumer {socket_id}: Buffer not found or connection closed") break # 獲取所有消息 messages = buffer.get_all() if messages: print(f"Consumer {socket_id}: Received {len(messages)} messages") for msg in messages: # 處理每條消息 (這裡只是示例,實際應用中可能有更複雜的處理) print(f" - Message from SysID={msg.get_srcSystem()}, CompID={msg.get_srcComponent()}, Type={msg.get_type()}") # 短暫休眠,避免 CPU 空轉 time.sleep(0.2) except Exception as e: print(f"Consumer {socket_id} stopped: {e}") def send_command_thread(io_manager, socket_ids): """定期向所有連接發送命令""" print("Starting command sender thread...") # 創建一個 MAVLink 實例用於生成消息 mav = mavlink2.MAVLink(None) mav.srcSystem = 255 # GCS system ID mav.srcComponent = 0 try: count = 0 while True: # 等待 2 秒 time.sleep(2.0) count += 1 # 創建一個命令消息 msg = mavlink2.MAVLink_command_long_message( target_system=1, target_component=1, command=mavlink2.MAV_CMD_REQUEST_PROTOCOL_VERSION, confirmation=0, param1=0, param2=0, param3=0, param4=0, param5=0, param6=0, param7=0 ) # 向所有連接發送消息 for socket_id in socket_ids: if socket_id in io_manager.connections and not io_manager.connections[socket_id].is_closed: try: # 打包並發送消息 result = io_manager.send_message(socket_id, msg) print(f"Sent command to socket {socket_id}: {'Success' if result else 'Failed'}") except Exception as e: print(f"Error sending to socket {socket_id}: {e}") # 每 10 次迭代關閉一個連接 (用於演示關閉功能) if count % 10 == 0 and socket_ids: socket_id = socket_ids.pop(0) print(f"Closing connection {socket_id}...") io_manager.remove_connection(socket_id) except Exception as e: print(f"Command sender thread stopped: {e}") def main(): print("AsyncIOManager Example") print("======================") # 創建 AsyncIOManager 實例 io_manager = AsyncIOManager() # 啟動 I/O 管理器 io_manager.start() print("AsyncIOManager started") # 創建模擬 MAVLink socket mock_sockets = create_mock_mavlink_sockets(5) socket_ids = [] # 註冊連接 for i, socket in enumerate(mock_sockets): socket_id = io_manager.register_connection(socket) socket_ids.append(socket_id) print(f"Registered socket {i} with ID {socket_id}") # 啟動監視執行緒 monitor = threading.Thread(target=monitor_thread, args=(io_manager,)) monitor.daemon = True monitor.start() # 為每個連接啟動消費者執行緒 consumers = [] for socket_id in socket_ids: consumer = threading.Thread(target=consumer_thread, args=(io_manager, socket_id)) consumer.daemon = True consumer.start() consumers.append(consumer) # 啟動命令發送執行緒 sender = threading.Thread(target=send_command_thread, args=(io_manager, socket_ids.copy())) sender.daemon = True sender.start() print("\nPress Ctrl+C to exit...") try: # 運行一段時間然後退出 time.sleep(30) except KeyboardInterrupt: pass finally: # 清理資源 print("\nShutting down...") io_manager.stop() print("AsyncIOManager stopped") if __name__ == "__main__": main()