2.15.26
This commit is contained in:
+64
-15
@@ -709,6 +709,12 @@ class NetworkManager:
|
||||
"""线程安全地将消息加入队列(公共方法)"""
|
||||
self._enqueue((msg_type, data_dict), high)
|
||||
|
||||
def safe_enqueue_and_wait(self, data_dict, msg_type=2, high=False, timeout_ms=30000):
|
||||
"""将消息加入队列,并等待网络线程确认已写入 TCP 连接。"""
|
||||
sent_event = threading.Event()
|
||||
self._enqueue((msg_type, data_dict, sent_event), high)
|
||||
return bool(sent_event.wait(max(0, int(timeout_ms)) / 1000.0))
|
||||
|
||||
def connect_server(self):
|
||||
"""
|
||||
连接到服务器(自动选择WiFi或4G)
|
||||
@@ -721,7 +727,7 @@ class NetworkManager:
|
||||
if self._network_type == "wifi":
|
||||
return self._check_wifi_connection()
|
||||
elif self._network_type == "4g":
|
||||
return True # 4G连接状态由AT命令维护
|
||||
return self._check_4g_connection()
|
||||
return False
|
||||
|
||||
# 自动选择网络
|
||||
@@ -738,6 +744,37 @@ class NetworkManager:
|
||||
return self._connect_tcp_via_4g()
|
||||
return False
|
||||
|
||||
def _check_4g_connection(self):
|
||||
"""检查4G TCP连接是否仍然有效(通过查询PDP地址验证网络附着状态)"""
|
||||
try:
|
||||
atc = hardware_manager.at_client
|
||||
if atc is None:
|
||||
return False
|
||||
if not self._uart4g_lock.acquire(timeout=3000):
|
||||
# 获取锁超时说明有其他操作在进行,视为连接仍有效
|
||||
return True
|
||||
try:
|
||||
r = atc.send("AT+CGPADDR=1", "OK", 3000)
|
||||
m = re.search(r'\+CGPADDR:\s*1,"([^"]+)"', r)
|
||||
ip = m.group(1) if m else ""
|
||||
if ip and ip != "0.0.0.0":
|
||||
return True
|
||||
# 无IP或IP无效,尝试重新激活PDP
|
||||
self.logger.warning("[4G-TCP] PDP地址无效,尝试重新激活")
|
||||
atc.send("AT+MIPCALL=1,1", "OK", 15000)
|
||||
r2 = atc.send("AT+CGPADDR=1", "OK", 3000)
|
||||
m2 = re.search(r'\+CGPADDR:\s*1,"([^"]+)"', r2)
|
||||
ip2 = m2.group(1) if m2 else ""
|
||||
if ip2 and ip2 != "0.0.0.0":
|
||||
return True
|
||||
self.logger.error("[4G-TCP] 重新激活PDP仍无有效IP,连接已断开")
|
||||
return False
|
||||
finally:
|
||||
self._uart4g_lock.release()
|
||||
except Exception as e:
|
||||
self.logger.warning(f"[4G-TCP] 连接检查异常: {e}")
|
||||
return True # 异常时不误判断线
|
||||
|
||||
def _wrap_wifi_tls(self, plain_sock, hostname):
|
||||
"""
|
||||
在已建立的 TCP socket 上做 TLS(WiFi 走主机 ssl 库;4G 仍用模组 AT+SSL)。
|
||||
@@ -864,6 +901,12 @@ class NetworkManager:
|
||||
"""检查WiFi TCP连接是否仍然有效"""
|
||||
if not wifi_manager.wifi_socket:
|
||||
return False
|
||||
# TLS socket 无法可靠使用 MSG_PEEK,但物理 WiFi 链路仍可通过 STA 关联状态判断。
|
||||
if not wifi_manager.is_sta_associated():
|
||||
self.logger.warning("[WIFI-TCP] STA 已断开,关闭 WiFi TCP 并重新选网")
|
||||
wifi_manager.disconnect_wifi()
|
||||
self._tcp_connected = False
|
||||
return False
|
||||
# TLS(ssl.wrap_socket/SSLContext.wrap_socket) 后的 socket 往往不支持 MSG_PEEK/MSG_DONTWAIT。
|
||||
# 这种情况下“主动探测”反而容易误报断线;让真正的 send/recv 去判定更稳。
|
||||
try:
|
||||
@@ -1085,6 +1128,8 @@ class NetworkManager:
|
||||
total += n
|
||||
|
||||
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)
|
||||
if ("SEND OK" in r) or ("OK" in r) or ("+MIPSEND" in r):
|
||||
return True
|
||||
@@ -1177,6 +1222,14 @@ class NetworkManager:
|
||||
# 这里保持 socket 为非阻塞模式(连接时已 setblocking(False))。
|
||||
# 不要反复 settimeout(),否则会把 socket 切回"阻塞+超时",并导致 conncheck 误报 timed out。
|
||||
data = wifi_manager.wifi_socket.recv(4096) # 每次最多接收4KB(无数据会抛 BlockingIOError)
|
||||
if data == b"":
|
||||
self.logger.warning("[WIFI-TCP] 对端已关闭连接")
|
||||
try:
|
||||
wifi_manager.wifi_socket.close()
|
||||
except Exception:
|
||||
pass
|
||||
wifi_manager.wifi_socket = None
|
||||
self._tcp_connected = False
|
||||
return data
|
||||
|
||||
except BlockingIOError:
|
||||
@@ -1777,16 +1830,9 @@ class NetworkManager:
|
||||
self.logger.info("[NET] TCP主线程启动")
|
||||
|
||||
send_hartbeat_fail_count = 0
|
||||
last_charging_check = 0
|
||||
CHARGING_CHECK_INTERVAL = 5000 # 5秒检查一次充电状态
|
||||
|
||||
while True:
|
||||
try:
|
||||
# 检查充电状态(每5秒检查一次)
|
||||
current_time = time.ticks_ms()
|
||||
if current_time - last_charging_check > CHARGING_CHECK_INTERVAL:
|
||||
last_charging_check = current_time
|
||||
|
||||
# OTA 期间不要 connect/登录/心跳/发送
|
||||
try:
|
||||
from ota_manager import ota_manager
|
||||
@@ -1799,7 +1845,7 @@ class NetworkManager:
|
||||
continue
|
||||
|
||||
if not self.connect_server():
|
||||
time.sleep_ms(5000)
|
||||
time.sleep_ms(1000)
|
||||
continue
|
||||
|
||||
# 发送登录包
|
||||
@@ -1820,7 +1866,7 @@ class NetworkManager:
|
||||
self.disconnect_server()
|
||||
except:
|
||||
pass
|
||||
time.sleep_ms(2000)
|
||||
time.sleep_ms(500)
|
||||
continue
|
||||
|
||||
self.logger.info("➡️ 登录包已发送,等待确认...")
|
||||
@@ -2264,7 +2310,8 @@ class NetworkManager:
|
||||
item_is_high = False
|
||||
|
||||
if item:
|
||||
msg_type, data_dict = item
|
||||
msg_type, data_dict = item[:2]
|
||||
sent_event = item[2] if len(item) > 2 else None
|
||||
pkt = self._netcore.make_packet(msg_type, data_dict)
|
||||
if not self.tcp_send_raw(pkt):
|
||||
# 发送失败:将消息放回队首(队列满则丢弃)
|
||||
@@ -2281,6 +2328,8 @@ class NetworkManager:
|
||||
except:
|
||||
pass
|
||||
break
|
||||
if sent_event is not None:
|
||||
sent_event.set()
|
||||
|
||||
# 发送激光校准结果
|
||||
if logged_in:
|
||||
@@ -2309,8 +2358,8 @@ class NetworkManager:
|
||||
pass
|
||||
break
|
||||
else:
|
||||
# 不立即断开,让下一轮心跳再试;同时缩短一点等待,提升恢复速度
|
||||
time.sleep_ms(200)
|
||||
# 不立即断开,让下一轮心跳再试
|
||||
time.sleep_ms(50)
|
||||
continue
|
||||
else:
|
||||
send_hartbeat_fail_count = 0
|
||||
@@ -2340,8 +2389,8 @@ class NetworkManager:
|
||||
self._send_event.clear()
|
||||
|
||||
self._tcp_connected = False
|
||||
self.logger.error("连接异常,2秒后重连...")
|
||||
time.sleep_ms(200)
|
||||
self.logger.error("连接异常,50ms后重连...")
|
||||
time.sleep_ms(50)
|
||||
|
||||
except Exception as e:
|
||||
# TCP主循环的顶层异常捕获,防止线程静默退出
|
||||
|
||||
Reference in New Issue
Block a user