commit to merge

serial port 功能已驗證
chiyu
Chiyu Chen 5 months ago
parent f31cc8742a
commit 5134fa8466

@ -37,7 +37,8 @@ class PanelState:
self.mavlink_bridge_state = "Stopped"
self.object_manager_state = "Stopped"
self.serial_manager_state = "Stopped"
self.socket_object_list = []
self.socket_object_list = [] # 已有的 mavlink object
self.linked_serial_dict = {} # 已連線的 serial 端口
self.panel_info_msg_list = [] # 顯示在面板上的資訊訊息
# 這邊是儲存關於 socket object 的資料
@ -128,6 +129,8 @@ class ControlPanel:
return user_input
# ================ 關於 mavlink object 的部份 ===================
def create_object_list_menu(self, state: PanelState, page=0, items_per_page=8):
"""動態創建 mavlink_object 列表選單(支持分頁)"""
children = []
@ -156,55 +159,6 @@ class ControlPanel:
child.socket_id = socket_id
children.append(obj_menu)
# 添加分頁控制
if total_pages > 1:
children.append(MenuNode("---", "---", None))
if page > 0:
prev_node = MenuNode("◀ 上一頁", f"{page}/{total_pages}", "PREV_PAGE")
prev_node.page = page - 1
children.append(prev_node)
if page < total_pages - 1:
next_node = MenuNode("下一頁 ▶", f"{page + 2}/{total_pages}", "NEXT_PAGE")
next_node.page = page + 1
children.append(next_node)
children.append(MenuNode("返回", "回到上層選單", "BACK"))
menu = MenuNode("Object List", f"連結口列表 (第 {page + 1} 頁)", children=children)
menu.current_page = page
return menu
def create_serial_port_menu(self, state: PanelState, page=0, items_per_page=8):
"""動態創建 serial port 列表選單(支持分頁)"""
children = []
# 獲取可用的 Serial 連接埠列表
# serial_ports = acquireSerial.get_serial_ports() # debug 全部抓一抓
serial_ports = acquireSerial.get_serial_ports_with_filter('/dev/ttyUSB*')
if not serial_ports:
children.append(MenuNode("(空)", "目前沒有串口設備", None))
else:
total_items = len(serial_ports)
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)
# 顯示當前頁的串口
for port in serial_ports[start_idx:end_idx]:
port_menu = MenuNode(f"{port}", children=[
MenuNode("Set Comm Type", "設定通訊形態", "SET_SERIAL_COMM", children=[
MenuNode("XBee(API-AT)", "XBee 模式", "SET_SERIAL_COMM_XBEE"),
# MenuNode("Telemetry", "數傳模式", "SET_SERIAL_COMM_TELEMETRY"),
]),
MenuNode("Set Baud", "設定 Baud", "TEXT_BAUD_SERIAL"),
MenuNode("Create", "建立此串口", "CREATE_SERIAL_PORT"),
MenuNode("返回", "回到列表", "BACK"),
])
# 將 port 附加到每個子選單項目上
for child in port_menu.children:
child.port = port
children.append(port_menu)
# 添加分頁控制
if total_pages > 1:
children.append(MenuNode("---", f"{page+1}/{total_pages}", None))
@ -218,7 +172,7 @@ class ControlPanel:
children.append(next_node)
children.append(MenuNode("返回", "回到上層選單", "BACK"))
menu = MenuNode("Serial Port List", f"口列表 (第 {page + 1} 頁)", children=children)
menu = MenuNode("Object List", f"連結口列表 (第 {page + 1} 頁)", children=children)
menu.current_page = page
return menu
@ -320,6 +274,106 @@ class ControlPanel:
stdscr.refresh()
return None
# ================ 關於 serial link 的部份 ===================
def create_serial_port_menu(self, state: PanelState, page=0, items_per_page=8):
"""動態創建 serial port 列表選單(支持分頁)"""
children = []
# 獲取可用的 Serial 連接埠列表
# serial_ports = acquireSerial.get_serial_ports() # debug 全部抓一抓
serial_ports = acquireSerial.get_serial_ports_with_filter('/dev/ttyUSB*')
if not serial_ports:
children.append(MenuNode("(空)", "目前沒有串口設備", None))
else:
total_items = len(serial_ports)
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)
# 顯示當前頁的串口
for port in serial_ports[start_idx:end_idx]:
port_menu = MenuNode(f"{port}", children=[
MenuNode("Set Comm Type", "設定通訊形態", "SET_SERIAL_COMM", children=[
MenuNode("XBee(API-AT)", "XBee 模式", "SET_SERIAL_COMM_XBEE"),
# MenuNode("Telemetry", "數傳模式", "SET_SERIAL_COMM_TELEMETRY"),
]),
MenuNode("Set Baud", "設定 Baud", "TEXT_BAUD_SERIAL"),
MenuNode("Create", "建立此串口", "CREATE_SERIAL_PORT"),
MenuNode("返回", "回到列表", "BACK"),
])
# 將 port 附加到每個子選單項目上
for child in port_menu.children:
child.port = port
children.append(port_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("返回", "回到上層選單", "BACK"))
menu = MenuNode("Serial Port List", f"串口列表 (第 {page + 1} 頁)", children=children)
menu.current_page = page
return menu
def create_linked_serial_menu(self, state: PanelState, page=0, items_per_page=8):
"""動態創建 已連線的 serial port 列表選單(支持分頁)並包含後續管理功能"""
children = []
if not state.linked_serial_dict:
children.append(MenuNode("(空)", "目前沒有連結口", None))
else:
total_items = len(state.linked_serial_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)
# 顯示當前頁的物件
linked_serial_id_list = list(state.linked_serial_dict.keys())
for serial_id in linked_serial_id_list[start_idx:end_idx]:
# 為每個 socket 創建子選單
obj_menu = MenuNode(f"Serial #{serial_id}", f"連結口 {serial_id}", None, children=[
MenuNode("Info", "查看詳細資訊", "INSPECT_LINKED_SERIAL"),
MenuNode("Remove", "移除此連結口", "REMOVE_LINKED_SERIAL"),
# MenuNode("Change UDP Target", "變更目標 UDP (工程)", "CHANGE_LINKED_SERIAL_TARGET"),
MenuNode("返回", "回到列表", "BACK"),
])
# 將 serial_id 附加到每個子選單項目上
for child in obj_menu.children:
child.serial_id = serial_id
children.append(obj_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("返回", "回到上層選單", "BACK"))
menu = MenuNode("Linked Serial List", f"連結口列表 (第 {page + 1} 頁)", children=children)
menu.current_page = page
return menu
def show_linked_serial_info(self):
pass
# ================ 關於 主要選單 的部份 ===================
def menu_tree(self):
"""建立多層選單結構"""
return MenuNode("Main Menu", children=[
@ -604,6 +658,11 @@ class ControlPanel:
menu_stack.append(created_list_menu)
idx_stack.append(0)
elif selected.action == "LIST_SERIAL_LINKS":
created_list_menu = self.create_linked_serial_menu(state, page=0)
menu_stack.append(created_list_menu)
idx_stack.append(0)
elif selected.action == "LIST_MAV_OBJECT":
# 動態生成 mavlink_object 列表選單
created_list_menu = self.create_object_list_menu(state, page=0)
@ -621,6 +680,8 @@ class ControlPanel:
created_list_menu = self.create_serial_port_menu(state, page=selected.page)
elif current_list_menu.name == "Object List":
created_list_menu = self.create_object_list_menu(state, page=selected.page)
elif current_list_menu.name == "Linked Serial List":
created_list_menu = self.create_linked_serial_menu(state, page=selected.page)
else:
# 不支援的選單類型,回到原本的選單
menu_stack.append(current_list_menu)
@ -763,6 +824,9 @@ class Orchestrator:
else:
self.panelState.serial_manager_state = 'Stopped'
linked_serial_dict = self.plumber.get_serial_link()
self.panelState.linked_serial_dict = linked_serial_dict
# 取出面板丟過來的「動作」
try:
cmd = self.cmd_q.get_nowait()

@ -473,7 +473,6 @@ class serial_manager:
logger.error(f"Failed to create serial link for {serial_port}: {e}")
return False
async def _async_create_serial_link(self, serial_port, baudrate, target_port, receiver_type: SerialReceiverType):
"""在事件循環線程中執行實際的連接創建"""
try:
@ -579,6 +578,12 @@ class serial_manager:
logger.error(f"Exception in _async_remove_serial_link for {serial_id}: {str(e)}")
return False
def get_serial_link(self):
ret = {} # serial id num : serial_port string
for key, obj in self.serial_objects.items():
ret[key] = obj.serial_port
return ret
@staticmethod
def check_serial_port(serial_port, baudrate):
"""檢查串口是否存在與可用"""
@ -619,5 +624,8 @@ if __name__ == '__main__':
UDP_REMOTE_PORT = 14571
sm.create_serial_link(SERIAL_PORT, SERIAL_BAUDRATE, UDP_REMOTE_PORT, SerialReceiverType.XBEEAPI2AT)
linked_serial = sm.get_serial_link()
print(linked_serial)
time.sleep(10)
sm.shutdown()
Loading…
Cancel
Save