This commit is contained in:
yrx
2026-08-12 14:59:13 +08:00
parent 165eeff64e
commit dc5da0294f
14 changed files with 202 additions and 15 deletions
+120 -3
View File
@@ -67,6 +67,7 @@ class NetworkManager:
self._queue_lock = threading.Lock()
self._send_event = threading.Event()
self._uart4g_lock = threading.Lock()
self._terminal_send_event = threading.Event()
self._device_id = None
self._password = None
self._raw_line_data = []
@@ -676,7 +677,7 @@ class NetworkManager:
except OSError:
pass
w = network.wifi.Wifi()
e = w.connect(ssid, password, wait=True, timeout=15)
e = w.connect(ssid, password, wait=True, timeout=10)
err.check_raise(e, "connect wifi failed")
if self.logger:
self.logger.info(f"[ota] Connect success, got ip{w.get_ip()}")
@@ -715,6 +716,29 @@ class NetworkManager:
self._enqueue((msg_type, data_dict, sent_event), high)
return bool(sent_event.wait(max(0, int(timeout_ms)) / 1000.0))
def safe_replace_queue_and_wait(self, data_dict, msg_type=2, timeout_ms=30000):
"""Drop queued messages, enqueue one terminal message, and wait for its TCP write."""
sent_event = threading.Event()
with self._queue_lock:
self._high_send_queue.clear()
self._normal_send_queue.clear()
self._high_send_queue.append((msg_type, data_dict, sent_event))
self._send_event.set()
return bool(sent_event.wait(max(0, int(timeout_ms)) / 1000.0))
def safe_terminal_send_and_wait(self, data_dict, msg_type=2, timeout_ms=30000):
"""Cancel ordinary 4G waits and replace queued work with one terminal message."""
sent_event = threading.Event()
result = {"sent": False}
self._terminal_send_event.set()
with self._queue_lock:
self._high_send_queue.clear()
self._normal_send_queue.clear()
self._high_send_queue.append((msg_type, data_dict, sent_event, "terminal", result))
self._send_event.set()
completed = sent_event.wait(max(0, int(timeout_ms)) / 1000.0)
return bool(completed and result["sent"])
def connect_server(self):
"""
连接到服务器(自动选择WiFi或4G)
@@ -1114,8 +1138,12 @@ class NetworkManager:
return False
try:
for _ in range(max_retries):
if self._terminal_send_event.is_set():
return False
cmd = f'AT+MIPSEND={link_id},{len(data)}'
if ">" not in hardware_manager.at_client.send(cmd, ">", 2000):
if self._terminal_send_event.is_set():
return False
time.sleep_ms(50)
continue
@@ -1130,14 +1158,73 @@ class NetworkManager:
hardware_manager.uart4g.write(b"\x1A")
with hardware_manager.at_client._q_lock:
hardware_manager.at_client._rx = b""
r = hardware_manager.at_client.send("", "OK", 8000)
r = hardware_manager.at_client.send(
"", "OK", 8000, abort_event=self._terminal_send_event
)
if ("SEND OK" in r) or ("OK" in r) or ("+MIPSEND" in r):
return True
if self._terminal_send_event.is_set():
return False
time.sleep_ms(50)
return False
finally:
self._uart4g_lock.release()
def _tcp_send_terminal_raw(self, data: bytes) -> bool:
if not self._tcp_connected:
return False
if self._network_type == "wifi":
return self._tcp_send_raw_via_wifi(data, max_retries=1)
if self._network_type != "4g":
return False
link_id = getattr(config, "TCP_LINK_ID", 0)
lock_timeout_sec = float(
getattr(config, "CHARGING_4G_UART_LOCK_TIMEOUT_SEC", 2.5)
)
prompt_timeout_ms = int(
getattr(config, "CHARGING_4G_PROMPT_TIMEOUT_MS", 1500)
)
confirm_timeout_ms = int(
getattr(config, "CHARGING_4G_CONFIRM_TIMEOUT_MS", 1000)
)
lock_start_ms = time.ticks_ms()
if not self._uart4g_lock.acquire(timeout=max(0.0, lock_timeout_sec)):
self.logger.warning(
f"[CHARGE-4G] uart_lock timeout timeout_sec={lock_timeout_sec}"
)
return False
try:
lock_elapsed_ms = abs(time.ticks_diff(time.ticks_ms(), lock_start_ms))
cmd = f'AT+MIPSEND={link_id},{len(data)}'
prompt_start_ms = time.ticks_ms()
if ">" not in hardware_manager.at_client.send(
cmd, ">", max(0, prompt_timeout_ms)):
prompt_elapsed_ms = abs(time.ticks_diff(time.ticks_ms(), prompt_start_ms))
self.logger.warning(
f"[CHARGE-4G] prompt failed lock_ms={lock_elapsed_ms} "
f"prompt_ms={prompt_elapsed_ms}"
)
return False
prompt_elapsed_ms = abs(time.ticks_diff(time.ticks_ms(), prompt_start_ms))
confirm_start_ms = time.ticks_ms()
r = hardware_manager.at_client.send_raw_and_wait(
data,
expect="OK",
timeout_ms=max(0, confirm_timeout_ms),
suffix=b"\x1A",
)
confirm_elapsed_ms = abs(time.ticks_diff(time.ticks_ms(), confirm_start_ms))
sent = ("SEND OK" in r) or ("OK" in r) or ("+MIPSEND" in r)
self.logger.warning(
f"[CHARGE-4G] send_done lock_ms={lock_elapsed_ms} "
f"prompt_ms={prompt_elapsed_ms} confirm_ms={confirm_elapsed_ms} "
f"sent={sent}"
)
return sent
finally:
self._uart4g_lock.release()
def _configure_ssl_before_connect(self, link_id: int) -> bool:
"""按手册:MSSLCFG(auth) -> (可选) MSSLCERTWR -> MSSLCFG(cert) -> MIPCFG(ssl)"""
ssl_id = getattr(config, "SSL_ID", 1)
@@ -1874,12 +1961,25 @@ class NetworkManager:
pending_cleared = False
last_heartbeat_ack_time = time.ticks_ms()
last_heartbeat_send_time = time.ticks_ms()
last_wifi_sta_check_time = time.ticks_ms()
while True:
# 如果底层连接已断开,尽快跳出内层循环触发重连/重选网络
if not self._tcp_connected:
break
if self._network_type == "wifi":
now_ms = time.ticks_ms()
if abs(time.ticks_diff(now_ms, last_wifi_sta_check_time)) >= 1000:
last_wifi_sta_check_time = now_ms
if not wifi_manager.is_sta_associated():
self.logger.warning(
"[WIFI-TCP] STA disconnected; leave WiFi session and reselect network"
)
wifi_manager.disconnect_wifi()
self._tcp_connected = False
break
# OTA 期间暂停 TCP 活动
try:
from ota_manager import ota_manager
@@ -2312,8 +2412,23 @@ class NetworkManager:
if item:
msg_type, data_dict = item[:2]
sent_event = item[2] if len(item) > 2 else None
item_is_terminal = len(item) > 3 and item[3] == "terminal"
terminal_result = item[4] if item_is_terminal and len(item) > 4 else None
pkt = self._netcore.make_packet(msg_type, data_dict)
if not self.tcp_send_raw(pkt):
send_ok = (
self._tcp_send_terminal_raw(pkt)
if item_is_terminal
else self.tcp_send_raw(pkt)
)
if not send_ok:
if item_is_terminal:
if terminal_result is not None:
terminal_result["sent"] = False
if sent_event is not None:
sent_event.set()
break
if self._terminal_send_event.is_set():
continue
# 发送失败:将消息放回队首(队列满则丢弃)
with self.get_queue_lock():
if item_is_high:
@@ -2329,6 +2444,8 @@ class NetworkManager:
pass
break
if sent_event is not None:
if terminal_result is not None:
terminal_result["sent"] = True
sent_event.set()
# 发送激光校准结果