invole c++
This commit is contained in:
90
network.py
90
network.py
@@ -15,6 +15,7 @@ import os
|
||||
import threading
|
||||
import socket
|
||||
import config
|
||||
|
||||
from hardware import hardware_manager
|
||||
from power import get_bus_voltage, voltage_to_percent
|
||||
# from laser import laser_manager
|
||||
@@ -56,6 +57,23 @@ class NetworkManager:
|
||||
self._prefer_wifi = True # 是否优先使用WiFi
|
||||
self._wifi_recv_buffer = b"" # WiFi接收缓冲区
|
||||
self._initialized = True
|
||||
|
||||
# 导入 archery_netcore 模块,并检查是否存在 parse_packet 和 make_packet 函数
|
||||
try:
|
||||
import archery_netcore as _netcore
|
||||
self._netcore = _netcore
|
||||
if hasattr(self._netcore, "parse_packet") and hasattr(self._netcore, "make_packet") and hasattr(self._netcore, "actions_for_inner_cmd"):
|
||||
print("[NET] archery_netcore found")
|
||||
else:
|
||||
print("[NET] archery_netcore not found parse_packet or make_packet")
|
||||
exit(1)
|
||||
except Exception:
|
||||
print("[NET] import archery_netcore failed")
|
||||
exit(1)
|
||||
|
||||
# 服务器相关
|
||||
self._server_ip = self._netcore.get_config().get("SERVER_IP")
|
||||
self._server_port = self._netcore.get_config().get("SERVER_PORT")
|
||||
|
||||
# ==================== 状态访问(只读属性)====================
|
||||
|
||||
@@ -287,7 +305,7 @@ class NetworkManager:
|
||||
# 策略1:如果指定优先WiFi,且WiFi可用,使用WiFi
|
||||
if prefer_wifi and self.is_wifi_connected():
|
||||
# 检查WiFi是否能连接到服务器
|
||||
if self.is_server_reachable(config.SERVER_IP, config.SERVER_PORT, timeout=3):
|
||||
if self.is_server_reachable(self._server_ip, self._server_port, timeout=3):
|
||||
self._network_type = "wifi"
|
||||
self.logger.info(f"[NET] 选择WiFi网络,IP: {self._wifi_ip}")
|
||||
return "wifi"
|
||||
@@ -296,7 +314,7 @@ class NetworkManager:
|
||||
|
||||
# 策略2:如果WiFi可用,使用WiFi
|
||||
if self.is_wifi_connected():
|
||||
if self.is_server_reachable(config.SERVER_IP, config.SERVER_PORT, timeout=3):
|
||||
if self.is_server_reachable(self._server_ip, self._server_port, timeout=3):
|
||||
self._network_type = "wifi"
|
||||
self.logger.info(f"[NET] 选择WiFi网络,IP: {self._wifi_ip}")
|
||||
return "wifi"
|
||||
@@ -324,6 +342,27 @@ class NetworkManager:
|
||||
if len(data) < 12:
|
||||
return None, None
|
||||
body_len, msg_type, checksum = struct.unpack(">III", data[:12])
|
||||
|
||||
expected_len = 12 + body_len
|
||||
|
||||
# 防御性检查:如果 data 比预期长,说明可能有粘包
|
||||
if len(data) > expected_len:
|
||||
self.logger.warning(
|
||||
f"[TCP] parse_packet: data length ({len(data)}) > expected ({expected_len}), "
|
||||
f"possible packet concatenation. body_len={body_len}, msg_type={msg_type}"
|
||||
)
|
||||
# 只解析第一个包,忽略多余数据(或者可以返回剩余部分)
|
||||
# data = data[:expected_len]
|
||||
# TODO: 是否需要解析剩余部分?
|
||||
|
||||
# 如果 data 比预期短,说明包不完整(半包)
|
||||
if len(data) < expected_len:
|
||||
self.logger.warning(
|
||||
f"[TCP] parse_packet: data length ({len(data)}) < expected ({expected_len}), "
|
||||
f"incomplete packet. body_len={body_len}, msg_type={msg_type}"
|
||||
)
|
||||
return None, None
|
||||
|
||||
body = data[12:12 + body_len]
|
||||
try:
|
||||
return msg_type, json.loads(body.decode())
|
||||
@@ -395,7 +434,7 @@ class NetworkManager:
|
||||
link_id = getattr(config, "TCP_LINK_ID", 0)
|
||||
use_ssl = getattr(config, "USE_TCP_SSL", False)
|
||||
|
||||
host = config.SERVER_IP
|
||||
host = self._server_ip
|
||||
port = getattr(config, "TCP_SSL_PORT", 443) if use_ssl else config.SERVER_PORT
|
||||
tail = getattr(config, "MIPOPEN_TAIL", "")
|
||||
with self.get_uart_lock():
|
||||
@@ -641,31 +680,6 @@ class NetworkManager:
|
||||
SALT = "shootMessageFire"
|
||||
SALT2 = "shoot"
|
||||
return "Arrow_" + hmac.new((SALT + device_id).encode(), SALT2.encode(), hashlib.sha256).hexdigest()
|
||||
|
||||
|
||||
def send_http_cmd(self, cmd_str, timeout_ms=3000):
|
||||
"""发送 HTTP 相关 AT 指令(调试用)"""
|
||||
self.logger.debug(f"[HTTP AT] => {cmd_str}")
|
||||
return hardware_manager.at_client.send(cmd_str, "OK", timeout_ms)
|
||||
|
||||
|
||||
def upload_shoot_event(self,json_data):
|
||||
"""通过 4G 模块上报射击事件到 HTTP 接口(备用通道)"""
|
||||
token = self.generate_token(self.device_id)
|
||||
if not self.send_http_cmd(f'AT+MHTTPCREATE="{config.HTTP_URL}"'):
|
||||
return False
|
||||
instance_id = 0
|
||||
self.send_http_cmd(f'AT+MHTTPCFG="header",{instance_id},"Content-Type: application/json"')
|
||||
self.send_http_cmd(f'AT+MHTTPCFG="header",{instance_id},"Authorization: {token}"')
|
||||
self.send_http_cmd(f'AT+MHTTPCFG="header",{instance_id},"DeviceId: {self.device_id}"')
|
||||
json_str = ujson.dumps(json_data)
|
||||
if not self.send_http_cmd(f'AT+MHTTPCONTENT={instance_id},0,0,"{json_str}"'):
|
||||
return False
|
||||
if self.send_http_cmd(f'AT+MHTTPREQUEST={instance_id},2,0,"{config.HTTP_API_PATH}"'):
|
||||
time.sleep_ms(5000)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def tcp_main(self):
|
||||
"""TCP 主通信循环:登录、心跳、处理指令、发送数据"""
|
||||
@@ -709,7 +723,8 @@ class NetworkManager:
|
||||
"vol": vol_val,
|
||||
"vol_per": voltage_to_percent(vol_val)
|
||||
}
|
||||
if not self.tcp_send_raw(self.make_packet(1, login_data)):
|
||||
# if not self.tcp_send_raw(self.make_packet(1, login_data)):
|
||||
if not self.tcp_send_raw(self._netcore.make_packet(1, login_data)):
|
||||
self._tcp_connected = False
|
||||
time.sleep_ms(2000)
|
||||
continue
|
||||
@@ -777,7 +792,8 @@ class NetworkManager:
|
||||
except:
|
||||
pass
|
||||
|
||||
msg_type, body = self.parse_packet(payload)
|
||||
# msg_type, body = self.parse_packet(payload)
|
||||
msg_type, body = self._netcore.parse_packet(payload)
|
||||
|
||||
# 处理登录响应
|
||||
if not logged_in and msg_type == 1:
|
||||
@@ -845,8 +861,12 @@ class NetworkManager:
|
||||
if not laser_manager.calibration_active:
|
||||
laser_manager.turn_on_laser()
|
||||
time.sleep_ms(100)
|
||||
laser_manager.start_calibration()
|
||||
self.safe_enqueue({"result": "calibrating"}, 2)
|
||||
if not config.HARDCODE_LASER_POINT:
|
||||
laser_manager.start_calibration()
|
||||
self.safe_enqueue({"result": "calibrating"}, 2)
|
||||
else:
|
||||
# 写死的逻辑,不需要校准激光点
|
||||
self.safe_enqueue({"result": "laser pos set by hard code"}, 2)
|
||||
elif inner_cmd == 3: # 关闭激光
|
||||
from laser_manager import laser_manager
|
||||
laser_manager.turn_off_laser()
|
||||
@@ -962,7 +982,8 @@ class NetworkManager:
|
||||
self.get_queue_lock().release()
|
||||
|
||||
if msg_type is not None and data_dict is not None:
|
||||
pkt = self.make_packet(msg_type, data_dict)
|
||||
pkt = self._netcore.make_packet(msg_type, data_dict)
|
||||
# pkt = self.make_packet(msg_type, data_dict)
|
||||
if not self.tcp_send_raw(pkt):
|
||||
self._tcp_connected = False
|
||||
break
|
||||
@@ -979,7 +1000,8 @@ class NetworkManager:
|
||||
current_time = time.ticks_ms()
|
||||
if logged_in and current_time - last_heartbeat_send_time > config.HEARTBEAT_INTERVAL * 1000:
|
||||
vol_val = get_bus_voltage()
|
||||
if not self.tcp_send_raw(self.make_packet(4, {"vol": vol_val, "vol_per": voltage_to_percent(vol_val)})):
|
||||
if not self.tcp_send_raw(self._netcore.make_packet(4, {"vol": vol_val, "vol_per": voltage_to_percent(vol_val)})):
|
||||
# if not self.tcp_send_raw(self.make_packet(4, {"vol": vol_val, "vol_per": voltage_to_percent(vol_val)})):
|
||||
self.logger.error("心跳发送失败")
|
||||
time.sleep_ms(3000)
|
||||
send_hartbeat_fail_count += 1
|
||||
|
||||
Reference in New Issue
Block a user