Compare commits
2
Commits
f8f5ff5a15
...
fa0a2d0831
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa0a2d0831 | ||
|
|
c12959d964 |
@@ -0,0 +1,174 @@
|
|||||||
|
|
||||||
|
這個檔案整理 此專案下 程式代碼的流程與思路
|
||||||
|
只會挑出重要的變數與方法描述
|
||||||
|
以利後續開發使用
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 檔案結構
|
||||||
|
|
||||||
|
特別注意:
|
||||||
|
1. 有標註 [async method] 都是不該被直接呼叫的內部方法
|
||||||
|
|
||||||
|
- *valuable* 這個是變數 **沒有括號**
|
||||||
|
- *method (parameters...)* 這個是方法 **有括號**
|
||||||
|
|
||||||
|
## mainOrchestrator.py : 程式進入點
|
||||||
|
|
||||||
|
### **[Class]** Orchestrator
|
||||||
|
最上層的發配資源與啟動終端機面板的調配者
|
||||||
|
- *self.manager* 存放 async_io_manager 實例
|
||||||
|
- *self.bridge* 存放 mavlink_bridge 實例
|
||||||
|
- *self.plumber* 存放 serial_manager 實例
|
||||||
|
- *self.vehicle_registry* 存放 vehicle_registry 實例
|
||||||
|
|
||||||
|
- *self.panel_thread* 面板的執行緒
|
||||||
|
- *self.panelState* 暫存面板與調配者互動的資料流動區
|
||||||
|
- 面板運行狀態
|
||||||
|
- 面板操作結果
|
||||||
|
- 其他模組的運行狀態
|
||||||
|
---
|
||||||
|
- *mainLoop()* 核心方法
|
||||||
|
- 更新個模組狀態到 *self.panelState*
|
||||||
|
- 對應面板來的操作指令
|
||||||
|
---
|
||||||
|
對於 async_io_manager 控制實現
|
||||||
|
- *create_udp_object()*
|
||||||
|
- *delete_udp_object()*
|
||||||
|
- *add_target_to_object()*
|
||||||
|
- *remove_target_from_object()*
|
||||||
|
---
|
||||||
|
關於載具管理與檢視
|
||||||
|
- *_update_vehicles_list()*
|
||||||
|
- *_prepare_vehicle_info*
|
||||||
|
---
|
||||||
|
關於 serial_manager 控制實現
|
||||||
|
- *create_serial_port_object()*
|
||||||
|
|
||||||
|
|
||||||
|
### **[Class]** ControlPanel
|
||||||
|
面板的核心運行物件
|
||||||
|
把自己的變數 獨立出來都放到 PanelState 去
|
||||||
|
- *panel_thread()* 核心方法
|
||||||
|
- 主選單的引入
|
||||||
|
- 主選單下所有的按鍵操作
|
||||||
|
- 定義所有人為操作後續面板執行緒行為
|
||||||
|
- *menu_tree()* 基礎選單的定義檔
|
||||||
|
---
|
||||||
|
關於 udp object 的操作
|
||||||
|
- *create_object_list_menu()* object 選單的定義檔
|
||||||
|
- *show_object_info()* 顯示 object 資訊
|
||||||
|
- *select_target_socket()* object 對於轉拋功能的操作
|
||||||
|
---
|
||||||
|
關於 serial 的操作
|
||||||
|
- *create_serial_port_menu()*
|
||||||
|
- *create_linked_serial_menu()*
|
||||||
|
- *show_linked_serial_info()*
|
||||||
|
---
|
||||||
|
關於載具檢視與操作
|
||||||
|
- *create_vehicles_list_menu()*
|
||||||
|
- *show_vehicle_info()*
|
||||||
|
|
||||||
|
### **[Class]** PanelState
|
||||||
|
作為面板執行緒(ControlPanel)與調配者(Orchestrator)溝通的管道
|
||||||
|
不包含具體實作方法 是 ControlPanel 的延伸
|
||||||
|
- *self.panel_info_msg_list* 顯示在面板上的資訊訊息
|
||||||
|
|
||||||
|
## mavlinkObject.py
|
||||||
|
|
||||||
|
### 全域變數
|
||||||
|
- *stream_bridge_ring*
|
||||||
|
- *return_packet_ring*
|
||||||
|
|
||||||
|
### **[Class]** mavlink_bridge
|
||||||
|
唯一實例
|
||||||
|
實際去解析 mavlink 封包的地方
|
||||||
|
接收 stream_bridge_ring 與 return_packet_ring 的資料
|
||||||
|
這邊是比較偏自動化 不會被操作的
|
||||||
|
- *self.thread* 自己的執行緒
|
||||||
|
---
|
||||||
|
- *_run_thread()* 核心方法
|
||||||
|
- *_handle_XXXXX()* 每一種單項 mavlink 封包的解析
|
||||||
|
- *send_message()* 是 _send_to_socket() 的高階包裝 跟 ros2 介面做互動的方法
|
||||||
|
- *_send_to_socket()* 把要傳送的封包 丟給 mavlink 去處理
|
||||||
|
|
||||||
|
### **[Class]** async_io_manager
|
||||||
|
唯一實例
|
||||||
|
異步 event loop
|
||||||
|
沒有核心方法
|
||||||
|
這邊主要是管理 mavlink_object 的地方 (但不會對於某個 mavlink_object 內部需求做操作)
|
||||||
|
|
||||||
|
- *self.thread* 自己的執行緒
|
||||||
|
- *self.managed_objects* 資料結構 socket_id: mavlink_object
|
||||||
|
---
|
||||||
|
- *add_mavlink_object(mavlink_object)* [call method] 把一個 mavlink_object 物件加入管理
|
||||||
|
- *_async_add_mavlink_object(mavlink_object)* [async method] 對應上面的內部方法 不該直接使用
|
||||||
|
- *remove_mavlink_object(socket_id)* [call method] 從管理區把指定 mavlink_object 移除
|
||||||
|
|
||||||
|
### **[Class]** mavlink_object
|
||||||
|
儲存 mavlink socket
|
||||||
|
處理 mavlink 封包分流的地方
|
||||||
|
- *cls.mavlinkObjects* 資料結構 { socket_id(序號) : mavlink_object(物件實例) }
|
||||||
|
- *self.mavlink_socket* 從 pymavlink 繼承的socket物件
|
||||||
|
- *self.state* 描述這個 socket 物件的狀態
|
||||||
|
---
|
||||||
|
- *process_data()* [async method] 核心方法
|
||||||
|
- *remove_target_socket()* *add_target_socket()*
|
||||||
|
- *message_put_queue()* 把要傳送的封包放到自己這個物件的暫存區 會由 process_data() 依照異步流程被實際丟出
|
||||||
|
|
||||||
|
## serialManager.py
|
||||||
|
看這個檔案的重點再於要搞清楚 端口物件 還是 傳輸物件
|
||||||
|
|
||||||
|
### **[Class]** serial_manager
|
||||||
|
異步 event loop
|
||||||
|
管理 mavlink_object 的地方
|
||||||
|
- *self.thread* 自己的執行緒
|
||||||
|
- *self.loop* 自己的事件迴圈
|
||||||
|
---
|
||||||
|
- *create_serial_link()* [call method] 把 serial 端口跟 UDP 端口打通
|
||||||
|
- *_async_create_serial_link()* [async method] 把兩種端口接起來的重點程序
|
||||||
|
- *remove_serial_link()* [call method] 關閉指定的 serial 端口
|
||||||
|
- *_async_remove_serial_link()* [async method]
|
||||||
|
|
||||||
|
### **[Class]** serial_object
|
||||||
|
被塞在 serial_manager 裡面
|
||||||
|
只是一個變數物件
|
||||||
|
用來被儲存 serial 的資訊
|
||||||
|
- *self.transport*
|
||||||
|
- *self.protocol*
|
||||||
|
- *self.udp_handler* UDP 端口物件
|
||||||
|
- *self.serial_handler* Serial 端口物件
|
||||||
|
|
||||||
|
### **[Class]** UDPHandler
|
||||||
|
處理 UDP 收發的端口 作為一個端口物件
|
||||||
|
作為 UDP OutBound 使用 所以不會佔用系統監聽資源
|
||||||
|
- *self.transport* 自己的傳輸物件
|
||||||
|
---
|
||||||
|
- *datagram_received()* 先加碼成 Xbee 再呼叫 Serial 端口物件送出
|
||||||
|
|
||||||
|
### **[Class]** SerialHandler
|
||||||
|
處理 Serial 收發的端口 作為一個端口物件
|
||||||
|
- *self.transport* 自己的傳輸物件
|
||||||
|
---
|
||||||
|
- *data_received()* 先組合 Serial 封包 再解碼 再呼叫 UDP 端口物件送出
|
||||||
|
|
||||||
|
## mavlinkVehicleView.py
|
||||||
|
這個檔案是作為載具的資訊暫存庫使用 會搭配 ROS2 的功能 再做利用
|
||||||
|
|
||||||
|
# 開發記錄
|
||||||
|
|
||||||
|
## 已實現功能
|
||||||
|
1. mavlink 分流解析
|
||||||
|
2. mavlink socket 建立
|
||||||
|
3. mavlink socket 轉拋 proxy
|
||||||
|
4. 建立 Serial 轉 UDP 連結 並管理
|
||||||
|
5. 建立 serial 連線
|
||||||
|
6. 各單元模組化
|
||||||
|
7. 終端機介面控制
|
||||||
|
8. 基礎載具流量觀測
|
||||||
|
9. 載具狀態收集與彙整
|
||||||
|
|
||||||
|
### 待開發功能
|
||||||
|
5-1. 建立 serial 連線 並可以對接收器下達AT指令
|
||||||
|
5-2. 模組化 serial 連線機制 以利後期擴容其他模組
|
||||||
|
10-1. ros2 應用開發介面
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -323,7 +323,7 @@ class mavlink_bridge:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
mav_obj = mavlink_object.mavlinkObjects[socket_id]
|
mav_obj = mavlink_object.mavlinkObjects[socket_id]
|
||||||
return mav_obj.send_message(message_bytes)
|
return mav_obj.message_put_queue(message_bytes)
|
||||||
|
|
||||||
# 定義 mavlink_object 的狀態
|
# 定義 mavlink_object 的狀態
|
||||||
class MavlinkObjectState(Enum):
|
class MavlinkObjectState(Enum):
|
||||||
@@ -501,7 +501,7 @@ class mavlink_object:
|
|||||||
logger.error(f"Invalid return message types: {msg_types}")
|
logger.error(f"Invalid return message types: {msg_types}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def send_message(self, message_bytes):
|
def message_put_queue(self, message_bytes):
|
||||||
"""
|
"""
|
||||||
從主線程向此 mavlink_object 的 socket 發送數據
|
從主線程向此 mavlink_object 的 socket 發送數據
|
||||||
將數據添加到簡單的列表中,由 asyncio 任務處理
|
將數據添加到簡單的列表中,由 asyncio 任務處理
|
||||||
@@ -568,9 +568,7 @@ class async_io_manager:
|
|||||||
self.loop = None
|
self.loop = None
|
||||||
self.running = False
|
self.running = False
|
||||||
# self.main_task = None
|
# self.main_task = None
|
||||||
self.managed_objects = {} # socket_id: mavlink_object
|
|
||||||
self.thread = None
|
self.thread = None
|
||||||
self._stop_event = threading.Event()
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.loop = None
|
self.loop = None
|
||||||
@@ -586,7 +584,6 @@ class async_io_manager:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.running = True
|
self.running = True
|
||||||
self._stop_event.clear()
|
|
||||||
|
|
||||||
# 啟動獨立線程 命名為 AsyncIOManager
|
# 啟動獨立線程 命名為 AsyncIOManager
|
||||||
self.thread = threading.Thread(
|
self.thread = threading.Thread(
|
||||||
@@ -618,12 +615,11 @@ class async_io_manager:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# 停止所有被管理的 mavlink_object 所屬的 task
|
# 停止所有被管理的 mavlink_object 所屬的 task
|
||||||
for socket_id in list(self.managed_objects.keys()):
|
for socket_id in list(mavlink_object.mavlinkObjects.keys()):
|
||||||
self.remove_mavlink_object(socket_id)
|
self.remove_mavlink_object(socket_id)
|
||||||
|
|
||||||
# 停止自己的 task
|
# 停止自己的 task
|
||||||
self.running = False
|
self.running = False
|
||||||
self._stop_event.set()
|
|
||||||
|
|
||||||
# 解開事件循環的阻塞
|
# 解開事件循環的阻塞
|
||||||
self.loop.call_soon_threadsafe(self.loop.stop)
|
self.loop.call_soon_threadsafe(self.loop.stop)
|
||||||
@@ -663,16 +659,7 @@ class async_io_manager:
|
|||||||
self.running = False
|
self.running = False
|
||||||
logger.info("async_io_manager event loop END!")
|
logger.info("async_io_manager event loop END!")
|
||||||
|
|
||||||
async def _main_task(self): # 當初想說可能要一個額外的 task 來管理 但是目前好像用不掉 先放著不管
|
def add_mavlink_object(self, mavlink_obj: mavlink_object):
|
||||||
"""主任務協程 讓 async_io_manager 在執行緒中持續運作"""
|
|
||||||
logger.info("async_io_manager main task started")
|
|
||||||
|
|
||||||
while self.running and not self._stop_event.is_set():
|
|
||||||
await asyncio.sleep(0.1)
|
|
||||||
|
|
||||||
logger.info("async_io_manager main task ended")
|
|
||||||
|
|
||||||
def add_mavlink_object(self, mavlink_obj):
|
|
||||||
"""添加 mavlink_object"""
|
"""添加 mavlink_object"""
|
||||||
# 一個防呆 確保有 event loop 與 _main_task 正在運作
|
# 一個防呆 確保有 event loop 與 _main_task 正在運作
|
||||||
if not self.running or not self.loop:
|
if not self.running or not self.loop:
|
||||||
@@ -681,7 +668,10 @@ class async_io_manager:
|
|||||||
|
|
||||||
socket_id = mavlink_obj.socket_id
|
socket_id = mavlink_obj.socket_id
|
||||||
|
|
||||||
if socket_id in self.managed_objects:
|
# 檢查該對象是否已經在運行中
|
||||||
|
if socket_id in mavlink_object.mavlinkObjects:
|
||||||
|
existing_obj = mavlink_object.mavlinkObjects[socket_id]
|
||||||
|
if existing_obj.state == MavlinkObjectState.RUNNING:
|
||||||
logger.warning(f"mavlink_object {socket_id} already managed")
|
logger.warning(f"mavlink_object {socket_id} already managed")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -708,7 +698,6 @@ class async_io_manager:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
task = asyncio.create_task(mavlink_obj.process_data())
|
task = asyncio.create_task(mavlink_obj.process_data())
|
||||||
self.managed_objects[socket_id] = mavlink_obj
|
|
||||||
mavlink_obj.task = task
|
mavlink_obj.task = task
|
||||||
mavlink_obj.state = MavlinkObjectState.RUNNING
|
mavlink_obj.state = MavlinkObjectState.RUNNING
|
||||||
mavlink_obj.outgoing_msgs.clear()
|
mavlink_obj.outgoing_msgs.clear()
|
||||||
@@ -718,7 +707,7 @@ class async_io_manager:
|
|||||||
logger.error(f"Failed to create task for mavlink_object {socket_id}: {e}")
|
logger.error(f"Failed to create task for mavlink_object {socket_id}: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def remove_mavlink_object(self, socket_id):
|
def remove_mavlink_object(self, socket_id: int):
|
||||||
"""移除 mavlink_object"""
|
"""移除 mavlink_object"""
|
||||||
|
|
||||||
# 一個防呆 確保有 event loop 正在運作
|
# 一個防呆 確保有 event loop 正在運作
|
||||||
@@ -743,11 +732,11 @@ class async_io_manager:
|
|||||||
|
|
||||||
async def _async_remove_mavlink_object(self, socket_id):
|
async def _async_remove_mavlink_object(self, socket_id):
|
||||||
"""在事件循環線程中同步執行"""
|
"""在事件循環線程中同步執行"""
|
||||||
if socket_id not in self.managed_objects:
|
if socket_id not in mavlink_object.mavlinkObjects:
|
||||||
logger.warning(f"mavlink_object {socket_id} not managed")
|
logger.warning(f"mavlink_object {socket_id} not found")
|
||||||
return
|
return False
|
||||||
|
|
||||||
mavlink_obj = self.managed_objects[socket_id]
|
mavlink_obj = mavlink_object.mavlinkObjects[socket_id]
|
||||||
mavlink_obj.state = MavlinkObjectState.SHUTTINGDOWN
|
mavlink_obj.state = MavlinkObjectState.SHUTTINGDOWN
|
||||||
|
|
||||||
if not mavlink_obj.task.done():
|
if not mavlink_obj.task.done():
|
||||||
@@ -761,9 +750,8 @@ class async_io_manager:
|
|||||||
break
|
break
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
# 如果正常結束 則移除
|
# 如果正常結束 則設置為關閉狀態(物件的清理由 __del__ 處理)
|
||||||
if mavlink_obj.task.done():
|
if mavlink_obj.task.done():
|
||||||
del self.managed_objects[socket_id]
|
|
||||||
mavlink_obj.state = MavlinkObjectState.CLOSED
|
mavlink_obj.state = MavlinkObjectState.CLOSED
|
||||||
logger.info(f"Removed mavlink_object {socket_id} from manager.")
|
logger.info(f"Removed mavlink_object {socket_id} from manager.")
|
||||||
return True
|
return True
|
||||||
@@ -773,8 +761,9 @@ class async_io_manager:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def get_managed_objects(self):
|
def get_managed_objects(self):
|
||||||
"""獲取所有被管理的對象列表"""
|
"""獲取所有被管理的對象列表(狀態為 RUNNING 的對象)"""
|
||||||
return list(self.managed_objects.keys())
|
return [socket_id for socket_id, obj in mavlink_object.mavlinkObjects.items()
|
||||||
|
if obj.state == MavlinkObjectState.RUNNING]
|
||||||
|
|
||||||
# ====================== 分割線 =====================
|
# ====================== 分割線 =====================
|
||||||
|
|
||||||
@@ -807,9 +796,13 @@ if __name__ == '__main__':
|
|||||||
3. mavlink_bridge 的主要迴圈 增加 send_message 功能 可指定目標 sysid 或 socket_id 發送 mavlink 封包
|
3. mavlink_bridge 的主要迴圈 增加 send_message 功能 可指定目標 sysid 或 socket_id 發送 mavlink 封包
|
||||||
4. async_io_manager 循環邏輯大改動 優化 mavlink_object 加入與移除的邏輯 並使得 task 與 evenlt loop 分層更清楚
|
4. async_io_manager 循環邏輯大改動 優化 mavlink_object 加入與移除的邏輯 並使得 task 與 evenlt loop 分層更清楚
|
||||||
5. mavlink_object 移除不必要的 start 與 stop 方法 由 async_io_manager 統一管理其生命週期
|
5. mavlink_object 移除不必要的 start 與 stop 方法 由 async_io_manager 統一管理其生命週期
|
||||||
6. mavlink_object 優化 send_message 方法 避免無效判斷 與 增加一些防呆檢驗 並與 mavlink_bridge 連動工作
|
6. mavlink_object 優化 message_put_queue 方法 避免無效判斷 與 增加一些防呆檢驗 並與 mavlink_bridge 連動工作
|
||||||
7. 移除迴圈內的 try except 堆疊 增加效能
|
7. 移除迴圈內的 try except 堆疊 增加效能
|
||||||
8. 移除對於 mavlinkDevice 的依賴 改用 vehicle_registry 來管理所有的載具
|
8. 移除對於 mavlinkDevice 的依賴 改用 vehicle_registry 來管理所有的載具
|
||||||
|
|
||||||
|
2026年 01月 15日
|
||||||
|
1. async_io_manager.managed_objects 與 mavlink_object.mavlinkObjects 功能重複整合 保留 mavlink_object.mavlinkObjects
|
||||||
|
2. async_io_manager 的 _stop_event 無效變數移除
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ class VehicleView:
|
|||||||
"""
|
"""
|
||||||
if component_id not in self.components:
|
if component_id not in self.components:
|
||||||
self.components[component_id] = VehicleComponent(component_id, comp_type)
|
self.components[component_id] = VehicleComponent(component_id, comp_type)
|
||||||
logger.info(f"Added component {component_id} to system {self.sysid}")
|
# logger.info(f"Added component {component_id} to system {self.sysid}")
|
||||||
return self.components[component_id]
|
return self.components[component_id]
|
||||||
|
|
||||||
def get_component(self, component_id: int) -> Optional[VehicleComponent]:
|
def get_component(self, component_id: int) -> Optional[VehicleComponent]:
|
||||||
@@ -334,10 +334,17 @@ class VehicleView:
|
|||||||
"""移除組件"""
|
"""移除組件"""
|
||||||
if component_id in self.components:
|
if component_id in self.components:
|
||||||
del self.components[component_id]
|
del self.components[component_id]
|
||||||
logger.info(f"Removed component {component_id} from system {self.sysid}")
|
# logger.info(f"Removed component {component_id} from system {self.sysid}")
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def reset_component_stats(self, component_id: int) -> None:
|
||||||
|
"""重置指定組件的封包統計"""
|
||||||
|
component = self.get_component(component_id)
|
||||||
|
if component:
|
||||||
|
component.reset_packet_stats()
|
||||||
|
# logger.info(f"Reset packet stats for component {component_id} in system {self.sysid}")
|
||||||
|
|
||||||
def set_rf_module(self, rf_type: RFModuleType) -> RFModule:
|
def set_rf_module(self, rf_type: RFModuleType) -> RFModule:
|
||||||
"""設定RF模組"""
|
"""設定RF模組"""
|
||||||
self.rf_module = RFModule(rf_type)
|
self.rf_module = RFModule(rf_type)
|
||||||
@@ -435,3 +442,12 @@ class VehicleViewRegistry:
|
|||||||
|
|
||||||
# 全域註冊表實例
|
# 全域註冊表實例
|
||||||
vehicle_registry = VehicleViewRegistry()
|
vehicle_registry = VehicleViewRegistry()
|
||||||
|
|
||||||
|
'''
|
||||||
|
================= 改版記錄 ============================
|
||||||
|
|
||||||
|
2026.01.16
|
||||||
|
1. 新增 重置指定組件的封包統計 功能
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|||||||
@@ -187,11 +187,11 @@ class ATCommandHandler:
|
|||||||
# print(f"[{self.serial_port}] Serial Low: 0x{serial_low:08X}")
|
# print(f"[{self.serial_port}] Serial Low: 0x{serial_low:08X}")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# ====================== 分割線 =====================
|
||||||
|
|
||||||
class SerialHandler(asyncio.Protocol): # asyncio.Protocol 用於處理 Serial 收發
|
class SerialHandler(asyncio.Protocol): # asyncio.Protocol 用於處理 Serial 收發
|
||||||
def __init__(self, udp_handler, serial_port_str):
|
def __init__(self, udp_handler, serial_port_str):
|
||||||
self.udp_handler = udp_handler # UDP 的傳輸把手
|
self.udp_handler = udp_handler # UDP 的傳輸物件
|
||||||
self.serial_port_str = serial_port_str
|
self.serial_port_str = serial_port_str
|
||||||
self.at_handler = ATCommandHandler(serial_port_str)
|
self.at_handler = ATCommandHandler(serial_port_str)
|
||||||
|
|
||||||
@@ -327,8 +327,8 @@ class serial_manager:
|
|||||||
self.receiver_type = receiver_type
|
self.receiver_type = receiver_type
|
||||||
self.target_port = target_port # 指向的 UPD 端口
|
self.target_port = target_port # 指向的 UPD 端口
|
||||||
|
|
||||||
self.transport = None
|
self.transport = None # TODO 這個變數可能沒有作用
|
||||||
self.protocol = None
|
self.protocol = None # TODO 這個變數可能沒有作用
|
||||||
self.udp_handler = None
|
self.udp_handler = None
|
||||||
self.serial_handler = None
|
self.serial_handler = None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user