|
|
|
|
@ -21,6 +21,7 @@ from pymavlink import mavutil
|
|
|
|
|
# 自定義的 import
|
|
|
|
|
from . import mavlinkObject as mo
|
|
|
|
|
from . import serialManager as sm
|
|
|
|
|
from . import mavlinkVehicleView as mvv
|
|
|
|
|
|
|
|
|
|
from .utils import RingBuffer, setup_logger
|
|
|
|
|
from .utils import acquireSerial, acquirePort
|
|
|
|
|
@ -142,7 +143,7 @@ class ControlPanel:
|
|
|
|
|
children = []
|
|
|
|
|
|
|
|
|
|
if not state.socket_object_list:
|
|
|
|
|
children.append(MenuNode("(空)", "目前沒有連結口", None))
|
|
|
|
|
children.append(MenuNode("(Empty)", "目前沒有連結口", None))
|
|
|
|
|
else:
|
|
|
|
|
total_items = len(state.socket_object_list)
|
|
|
|
|
total_pages = (total_items + items_per_page - 1) // items_per_page
|
|
|
|
|
@ -158,7 +159,7 @@ class ControlPanel:
|
|
|
|
|
MenuNode("Cancel Link", "取消轉發連結", "MAVOBJ_CANCEL_LINK"),
|
|
|
|
|
MenuNode("Add Target", "添加轉發目標(工程)", "MAVOBJ_ADD_TARGET"),
|
|
|
|
|
MenuNode("Remove", "移除此連結口", "REMOVE_MAV_OBJECT"),
|
|
|
|
|
MenuNode("返回", "回到列表", "BACK"),
|
|
|
|
|
MenuNode("GoUp", "回到列表", "BACK"),
|
|
|
|
|
])
|
|
|
|
|
# 將 socket_id 附加到每個子選單項目上
|
|
|
|
|
for child in obj_menu.children:
|
|
|
|
|
@ -177,7 +178,7 @@ class ControlPanel:
|
|
|
|
|
next_node.page = page + 1
|
|
|
|
|
children.append(next_node)
|
|
|
|
|
|
|
|
|
|
children.append(MenuNode("返回", "回到上層選單", "BACK"))
|
|
|
|
|
children.append(MenuNode("GoUp", "回到上層選單", "BACK"))
|
|
|
|
|
menu = MenuNode("Object List", f"連結口列表 (第 {page + 1} 頁)", children=children)
|
|
|
|
|
menu.current_page = page
|
|
|
|
|
return menu
|
|
|
|
|
@ -294,10 +295,10 @@ class ControlPanel:
|
|
|
|
|
|
|
|
|
|
# 獲取可用的 Serial 連接埠列表
|
|
|
|
|
# serial_ports = acquireSerial.get_serial_ports() # debug 全部抓一抓
|
|
|
|
|
serial_ports = acquireSerial.get_serial_ports_with_filter('/dev/ttyUSB*')
|
|
|
|
|
serial_ports = acquireSerial.get_serial_ports_with_filter(['/dev/ttyUSB*', '/dev/ttyACM*'])
|
|
|
|
|
|
|
|
|
|
if not serial_ports:
|
|
|
|
|
children.append(MenuNode("(空)", "目前沒有串口設備", None))
|
|
|
|
|
children.append(MenuNode("(Empty)", "目前沒有串口設備", None))
|
|
|
|
|
else:
|
|
|
|
|
total_items = len(serial_ports)
|
|
|
|
|
total_pages = (total_items + items_per_page - 1) // items_per_page
|
|
|
|
|
@ -312,12 +313,12 @@ class ControlPanel:
|
|
|
|
|
# MenuNode("Telemetry", "數傳模式", "SET_SERIAL_COMM_TELEMETRY"),
|
|
|
|
|
]),
|
|
|
|
|
MenuNode("Set Baud", "設定 Baud", "TEXT_BAUD_SERIAL"),
|
|
|
|
|
MenuNode("Link to Middleware", "方便功能 可以直接建立 UDP object", "LINK_SERIAL_TO_MIDDLEWARE_UDP", children=[
|
|
|
|
|
MenuNode("Link to MW", "直接建立 Middleware UDP", "LINK_SERIAL_TO_MIDDLEWARE_UDP", children=[
|
|
|
|
|
MenuNode("Yes", action = "LINK_SERIAL_TO_MIDDLEWARE_UDP_YES"),
|
|
|
|
|
MenuNode("No", action = "LINK_SERIAL_TO_MIDDLEWARE_UDP_NO"),
|
|
|
|
|
]),
|
|
|
|
|
MenuNode("Create", "建立此串口", "CREATE_SERIAL_PORT"),
|
|
|
|
|
MenuNode("返回", "回到列表", "BACK"),
|
|
|
|
|
MenuNode("GoUp", "回到列表", "BACK"),
|
|
|
|
|
])
|
|
|
|
|
# 將 port 附加到每個子選單項目上
|
|
|
|
|
for child in port_menu.children:
|
|
|
|
|
@ -336,7 +337,7 @@ class ControlPanel:
|
|
|
|
|
next_node.page = page + 1
|
|
|
|
|
children.append(next_node)
|
|
|
|
|
|
|
|
|
|
children.append(MenuNode("返回", "回到上層選單", "BACK"))
|
|
|
|
|
children.append(MenuNode("GoUp", "回到上層選單", "BACK"))
|
|
|
|
|
menu = MenuNode("Serial Port List", f"串口列表 (第 {page + 1} 頁)", children=children)
|
|
|
|
|
menu.current_page = page
|
|
|
|
|
return menu
|
|
|
|
|
@ -346,7 +347,7 @@ class ControlPanel:
|
|
|
|
|
children = []
|
|
|
|
|
|
|
|
|
|
if not state.linked_serial_dict:
|
|
|
|
|
children.append(MenuNode("(空)", "目前沒有連結口", None))
|
|
|
|
|
children.append(MenuNode("(Empty)", "目前沒有連結口", None))
|
|
|
|
|
else:
|
|
|
|
|
total_items = len(state.linked_serial_dict)
|
|
|
|
|
total_pages = (total_items + items_per_page - 1) // items_per_page
|
|
|
|
|
@ -361,7 +362,7 @@ class ControlPanel:
|
|
|
|
|
MenuNode("Info", "查看詳細資訊", "INSPECT_LINKED_SERIAL"),
|
|
|
|
|
MenuNode("Remove", "移除此連結口", "REMOVE_LINKED_SERIAL"),
|
|
|
|
|
# MenuNode("Change UDP Target", "變更目標 UDP (工程)", "CHANGE_LINKED_SERIAL_TARGET"),
|
|
|
|
|
MenuNode("返回", "回到列表", "BACK"),
|
|
|
|
|
MenuNode("GoUp", "回到列表", "BACK"),
|
|
|
|
|
])
|
|
|
|
|
# 將 serial_id 附加到每個子選單項目上
|
|
|
|
|
for child in obj_menu.children:
|
|
|
|
|
@ -380,7 +381,7 @@ class ControlPanel:
|
|
|
|
|
next_node.page = page + 1
|
|
|
|
|
children.append(next_node)
|
|
|
|
|
|
|
|
|
|
children.append(MenuNode("返回", "回到上層選單", "BACK"))
|
|
|
|
|
children.append(MenuNode("GoUp", "回到上層選單", "BACK"))
|
|
|
|
|
menu = MenuNode("Linked Serial List", f"連結口列表 (第 {page + 1} 頁)", children=children)
|
|
|
|
|
menu.current_page = page
|
|
|
|
|
return menu
|
|
|
|
|
@ -435,6 +436,49 @@ class ControlPanel:
|
|
|
|
|
stdscr.clear()
|
|
|
|
|
stdscr.refresh()
|
|
|
|
|
|
|
|
|
|
# ================ 關於載具檢視的部份 ===================
|
|
|
|
|
|
|
|
|
|
def create_vehicles_list_menu(self, state: PanelState, page=0, items_per_page=8):
|
|
|
|
|
"""動態創建 已連線載具 列表選單(支持分頁)"""
|
|
|
|
|
children = []
|
|
|
|
|
|
|
|
|
|
if not state.connected_vehicles_dict:
|
|
|
|
|
children.append(MenuNode("(Empty)", "目前沒有已連線的載具", None))
|
|
|
|
|
else:
|
|
|
|
|
total_items = len(state.connected_vehicles_dict)
|
|
|
|
|
total_pages = (total_items + items_per_page - 1) // items_per_page
|
|
|
|
|
start_idx = page * items_per_page
|
|
|
|
|
end_idx = min(start_idx + items_per_page, total_items)
|
|
|
|
|
|
|
|
|
|
vehicle_id_list = list(state.connected_vehicles_dict.keys())
|
|
|
|
|
# 顯示當前頁的物件
|
|
|
|
|
for vehicle_id in vehicle_id_list[start_idx:end_idx]:
|
|
|
|
|
vehicle_menu = MenuNode(f"Vehicle #{vehicle_id}", f"載具 {vehicle_id}", None, children=[
|
|
|
|
|
MenuNode("Info", "查看詳細資訊", "INSPECT_VEHICLE"),
|
|
|
|
|
MenuNode("GoUp", "回到列表", "BACK"),
|
|
|
|
|
])
|
|
|
|
|
# 將 vehicle_id 附加到每個子選單項目上
|
|
|
|
|
for child in vehicle_menu.children:
|
|
|
|
|
child.vehicle_id = vehicle_id
|
|
|
|
|
children.append(vehicle_menu)
|
|
|
|
|
|
|
|
|
|
# 添加分頁控制
|
|
|
|
|
if total_pages > 1:
|
|
|
|
|
children.append(MenuNode("---", f"第 {page+1}/{total_pages} 頁", None))
|
|
|
|
|
if page > 0:
|
|
|
|
|
prev_node = MenuNode("◀ Prev", "上頁", "PREV_PAGE")
|
|
|
|
|
prev_node.page = page - 1
|
|
|
|
|
children.append(prev_node)
|
|
|
|
|
if page < total_pages - 1:
|
|
|
|
|
next_node = MenuNode("Next ▶", "下頁", "NEXT_PAGE")
|
|
|
|
|
next_node.page = page + 1
|
|
|
|
|
children.append(next_node)
|
|
|
|
|
|
|
|
|
|
children.append(MenuNode("GoUp", "回到上層選單", "BACK"))
|
|
|
|
|
menu = MenuNode("Connected Vehicles", f"已連線載具列表 (第 {page + 1} 頁)", children=children)
|
|
|
|
|
menu.current_page = page
|
|
|
|
|
return menu
|
|
|
|
|
|
|
|
|
|
# ================ 關於 主要選單 的部份 ===================
|
|
|
|
|
|
|
|
|
|
def menu_tree(self):
|
|
|
|
|
@ -457,8 +501,9 @@ class ControlPanel:
|
|
|
|
|
]),
|
|
|
|
|
MenuNode("Serial Manager", "Serial 連接埠選項", children=[
|
|
|
|
|
MenuNode("New+", "新增 Serial 連接埠", action = "LIST_SERIAL_RES"),
|
|
|
|
|
MenuNode("ListAll", "顯示已連線的 Serial", action = "LIST_SERIAL_LINKS"),
|
|
|
|
|
MenuNode("ListAll", "顯示並管理已連線的 Serial", action = "LIST_SERIAL_LINKS"),
|
|
|
|
|
]),
|
|
|
|
|
MenuNode("Vehicles Insp.", "檢視已連線的遠端載具", action = "INSPECT_VEHICLES"),
|
|
|
|
|
MenuNode("Engineer Mode", "工程模式", children=[
|
|
|
|
|
MenuNode("Stop Manager", "停止 Mavlink 物件管理", "STOP_MANAGER"),
|
|
|
|
|
MenuNode("Stop Bridge", "停止 Mavlink-ROS 橋接", "STOP_BRIDGE"),
|
|
|
|
|
@ -865,6 +910,8 @@ class Orchestrator:
|
|
|
|
|
self.stop_evt = stop_sig # 外部操作去中斷 "面板" 執行緒的訊號 (內部自己停止的話不需要用這個)
|
|
|
|
|
self.occupied_ip_ports = {} # 紀錄已被佔用的 ip:port 組合 "ip str" : [port int, port int, ...]
|
|
|
|
|
|
|
|
|
|
self.vehicle_registry = mvv.vehicle_registry
|
|
|
|
|
|
|
|
|
|
# === 1) 面板部分的準備 ===
|
|
|
|
|
self.cmd_q = queue.Queue()
|
|
|
|
|
self.panelState = PanelState() # 面板的狀態儲存
|
|
|
|
|
|