diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index dfdb8b7..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-*.sh text eol=lf
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 9d13be2..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-/cpp_ext/build/
-/.cursor/
-/dist/
-.idea
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 35410ca..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# 默认忽略的文件
-/shelf/
-/workspace.xml
-# 基于编辑器的 HTTP 客户端请求
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/.idea/archery.iml b/.idea/archery.iml
deleted file mode 100644
index 5550dcc..0000000
--- a/.idea/archery.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 105ce2d..0000000
--- a/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 261be2b..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 33066cd..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index c00e8fd..0000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "cmake.sourceDirectory": "E:/code/code/code/new/new/new/archery/cpp_ext"
-}
\ No newline at end of file
diff --git a/4g.py b/4g.py
deleted file mode 100644
index 6763c55..0000000
--- a/4g.py
+++ /dev/null
@@ -1,224 +0,0 @@
-# from maix import app, key, uart, pinmap, time
-# import hashlib
-# import hmac
-# import ujson
-
-# # 配置 UART2(用于 HTTP 上传)
-# pinmap.set_pin_function("A29", "UART2_RX")
-# pinmap.set_pin_function("A28", "UART2_TX")
-# http_serial = uart.UART("/dev/ttyS2", 115200, uart.BITS.BITS_8,
-# uart.PARITY.PARITY_NONE, uart.STOP.STOP_1)
-
-# # 按键初始化
-# key_triggered = False
-# def on_key_event(key_id, state):
-# global key_triggered
-# if state == key.State.KEY_PRESSED:
-# key_triggered = True
-# key_obj = key.Key(on_key_event)
-
-# # Token生成
-# def generate_token(device_id):
-# SALT = "shootMessageFire"
-# SALT2 = "shoot"
-# return "Arrow_" + hmac.new((SALT + device_id).encode(), SALT2.encode(), hashlib.sha256).hexdigest()
-
-# # 发送AT命令
-# http_instance_id = -1
-# def send_cmd(cmd_str, expect_create_id=False):
-# global http_instance_id
-# print("[AT指令] =>", cmd_str)
-# http_serial.write((cmd_str + "\r\n").encode())
-# buffer = b""
-# start = time.ticks_ms()
-# while time.ticks_ms() - start < 3000:
-# data = http_serial.read(128)
-# if data:
-# buffer += data
-# try:
-# decoded = buffer.decode()
-# print("返回:", decoded.strip())
-# if expect_create_id and "+MHTTPCREATE:" in decoded:
-# http_instance_id = int(decoded.split(":")[1].split("\r")[0].strip())
-# if "OK" in decoded: return True
-# if "+CME ERROR" in decoded or "ERROR" in decoded: return False
-# except:
-# print("解码异常")
-# time.sleep_ms(10)
-# return False
-
-# def create_http_instance(url):
-# return send_cmd(f'AT+MHTTPCREATE="{url}"', True) and http_instance_id != -1
-
-# def send_data(instance_id, token, api_path, json_data):
-# # 设置Header(使用统一的AT+MHTTPCFG="header")
-# send_cmd(f'AT+MHTTPCFG="header",{instance_id},"Content-Type: application/json"')
-# send_cmd(f'AT+MHTTPCFG="header",{instance_id},"Authorization: {token}"')
-# send_cmd(f'AT+MHTTPCFG="header",{instance_id},"DeviceId: {device_id}"')
-
-# # 发送Body数据
-# json_str = ujson.dumps(json_data)
-# send_cmd(f'AT+MHTTPCONTENT={instance_id},0,0,"{json_str}"')
-# send_cmd(f'AT+MHTTPREQUEST={instance_id},2,0,"{api_path}"')
-
-# def read_response(timeout_ms=5000):
-# start = time.ticks_ms()
-# while time.ticks_ms() - start < timeout_ms:
-# data = http_serial.read(128)
-# if data:
-# try:
-# print("响应:", data.decode("utf-8").strip())
-# except:
-# print("响应(raw):", data)
-# time.sleep_ms(50)
-
-# # 参数配置
-# device_id = "wZhC7kAZ" #需要根据实际硬件ID来测试
-# url = "http://ws.shelingxingqiu.com"
-# api_path = "/home/shoot/device_fire/arrow/fire"
-# token = generate_token(device_id)
-# print("生成Token:", token)
-
-# # 主循环:仅监听按键并上传模拟数据
-# while not app.need_exit():
-# if key_triggered:
-# key_triggered = False
-# print("按键按下,准备上传...")
-
-# # 模拟数据(可替换为实际测量值)
-# timestamp = int(time.time() * 1000)
-# json_data = {
-# "id": timestamp,
-# "DeviceId": device_id,
-# "x": 12.34,
-# "y": -5.67,
-# "rag": 90.0,
-# "time": timestamp,
-# "dst": 234.5,
-# "battery": 80,
-# "errorCode": 0
-# }
-
-# if http_instance_id == -1 and not create_http_instance(url):
-# print("创建 HTTP 实例失败")
-# elif http_instance_id != -1:
-# send_data(http_instance_id, token, api_path, json_data)
-# read_response()
-# else:
-# time.sleep_ms(100)
-from maix import app, uart, pinmap, time
-import hashlib
-import hmac
-import ujson
-
-# ========== 配置 ==========
-# UART2 for HTTP
-pinmap.set_pin_function("A29", "UART2_RX")
-pinmap.set_pin_function("A28", "UART2_TX")
-http_serial = uart.UART("/dev/ttyS2", 115200, uart.BITS.BITS_8,
- uart.PARITY.PARITY_NONE, uart.STOP.STOP_1)
-
-# 设备参数
-device_id = "wZhC7kAZ"
-url = "http://ws.shelingxingqiu.com"
-api_path = "/home/shoot/device_fire/arrow/fire"
-
-# ========== 工具函数 ==========
-def generate_token(device_id):
- SALT = "shootMessageFire"
- SALT2 = "shoot"
- return "Arrow_" + hmac.new((SALT + device_id).encode(), SALT2.encode(), hashlib.sha256).hexdigest()
-
-def send_cmd(cmd_str, timeout_ms=3000):
- """发送 AT 指令并等待 OK / ERROR"""
- print("[AT] =>", cmd_str)
- http_serial.write((cmd_str + "\r\n").encode())
- buffer = b""
- start = time.ticks_ms()
- while time.ticks_ms() - start < timeout_ms:
- data = http_serial.read(128)
- if data:
- buffer += data
- try:
- decoded = buffer.decode()
- print("<= ", decoded.strip())
- if "OK" in decoded:
- return True
- if "+CME ERROR" in decoded or "ERROR" in decoded:
- return False
- except:
- pass
- time.sleep_ms(10)
- return False
-
-def create_http_instance(url):
- cmd = f'AT+MHTTPCREATE="{url}"'
- if send_cmd(cmd):
- # 尝试提取 instance ID(如果模块返回)
- # 注意:部分模块不会返回 ID,可忽略,直接用 0 或 1
- return True
- return False
-
-def send_http_request(url, api_path, token, device_id, json_data):
- # 1. 创建 HTTP 实例
- if not create_http_instance(url):
- print("❌ 创建 HTTP 实例失败")
- return False
-
- # 2. 设置 Headers(假设实例 ID 为 0,或根据模块默认)
- instance_id = 0 # 大多数模块默认实例为 0;若支持多实例,需解析返回值
- send_cmd(f'AT+MHTTPCFG="header",{instance_id},"Content-Type: application/json"')
- send_cmd(f'AT+MHTTPCFG="header",{instance_id},"Authorization: {token}"')
- send_cmd(f'AT+MHTTPCFG="header",{instance_id},"DeviceId: {device_id}"')
-
- # 3. 发送 Body
- json_str = ujson.dumps(json_data)
- send_cmd(f'AT+MHTTPCONTENT={instance_id},0,0,"{json_str}"')
-
- # 4. 发起 POST 请求
- if send_cmd(f'AT+MHTTPREQUEST={instance_id},2,0,"{api_path}"'):
- print("✅ HTTP 请求已发送")
- return True
- else:
- print("❌ 发送请求失败")
- return False
-
-def read_response(timeout_ms=5000):
- print("⏳ 等待响应...")
- start = time.ticks_ms()
- while time.ticks_ms() - start < timeout_ms:
- data = http_serial.read(128)
- if data:
- try:
- print("📡 响应:", data.decode("utf-8").strip())
- except:
- print("📡 响应(raw):", data)
- time.sleep_ms(100)
-
-# ========== 主程序:直接上传 ==========
-print("🚀 启动直接上传流程...")
-
-token = generate_token(device_id)
-print("🔑 Token:", token)
-
-# 构造模拟数据
-timestamp = int(time.time() * 1000)
-json_data = {
- "id": timestamp,
- "DeviceId": device_id,
- "x": 12.34,
- "y": -5.67,
- "rag": 90.0,
- "time": timestamp,
- "dst": 234.5,
- "battery": 80,
- "errorCode": 0
-}
-
-# 执行上传
-if send_http_request(url, api_path, token, device_id, json_data):
- read_response()
-else:
- print("💥 上传流程失败")
-
-print("🔚 程序结束")
\ No newline at end of file
diff --git a/I2C.py b/I2C.py
deleted file mode 100644
index d6f4156..0000000
--- a/I2C.py
+++ /dev/null
@@ -1,88 +0,0 @@
-from maix import i2c, pinmap, time
-
-# 配置 I2C1 引脚(请根据实际连接修改)
-pinmap.set_pin_function("P18", "I2C1_SCL")
-pinmap.set_pin_function("P21", "I2C1_SDA")
-
-bus = i2c.I2C(1, i2c.Mode.MASTER)
-
-INA226_ADDR = 0x40
-
-# 寄存器定义
-REG_CONFIGURATION = 0x00
-REG_BUS_VOLTAGE = 0x02
-REG_CALIBRATION = 0x05
-
-# 校准值(不读取电流/功率时也可以省略)
-CALIBRATION_VALUE = 0x1400
-
-def write_register(reg, value):
- data = [(value >> 8) & 0xFF, value & 0xFF]
- bus.writeto_mem(INA226_ADDR, reg, bytes(data))
-
-def read_register(reg):
- data = bus.readfrom_mem(INA226_ADDR, reg, 2)
- return (data[0] << 8) | data[1]
-
-def init_ina226():
- write_register(REG_CONFIGURATION, 0x4527)
- write_register(REG_CALIBRATION, CALIBRATION_VALUE)
-
-def get_bus_voltage():
- raw = read_register(REG_BUS_VOLTAGE)
- return raw * 1.25 / 1000 # 单位 V
-
-def voltage_to_percent(voltage):
- if voltage >= 4.20:
- return 100
- elif voltage >= 4.15:
- return 95
- elif voltage >= 4.10:
- return 90
- elif voltage >= 4.05:
- return 85
- elif voltage >= 4.00:
- return 80
- elif voltage >= 3.95:
- return 75
- elif voltage >= 3.90:
- return 70
- elif voltage >= 3.85:
- return 65
- elif voltage >= 3.80:
- return 60
- elif voltage >= 3.75:
- return 55
- elif voltage >= 3.70:
- return 50
- elif voltage >= 3.65:
- return 45
- elif voltage >= 3.60:
- return 40
- elif voltage >= 3.55:
- return 35
- elif voltage >= 3.50:
- return 30
- elif voltage >= 3.45:
- return 25
- elif voltage >= 3.40:
- return 20
- elif voltage >= 3.35:
- return 15
- elif voltage >= 3.30:
- return 10
- elif voltage >= 3.20:
- return 5
- else:
- return 0
-
-# 初始化 INA226
-init_ina226()
-
-# 主循环,只显示电量百分比
-while True:
- voltage = get_bus_voltage()
- battery_percent = voltage_to_percent(voltage)
- print(f"当前电压: {voltage:.3f} V")
- print(f"估算电池电量: {battery_percent} %\n")
- time.sleep(2000)
diff --git a/README.md b/README.md
deleted file mode 100644
index 364f44f..0000000
--- a/README.md
+++ /dev/null
@@ -1,120 +0,0 @@
-
-# 🎯 激光射击系统(双版本)
-
-适用于 **MaixPy** 平台,支持远程控制、电池监测、Wi-Fi 连接及 OTA 升级。
-
-提供两个独立实现版本,共享相同网络协议与 OTA 机制,便于统一部署管理:
-
-- `main.py`:**视觉测距版**
-- `laser.py`:**激光测距版**
-
----
-
-## 📁 项目结构
-
-```
-laser_shooting_system/
-├── README.md
-├── main.py # 视觉测距版主程序
-└── laser.py # 激光测距版主程序
-```
-
----
-
-## ⚙️ 硬件依赖
-
-| 版本 | 必需硬件 |
-|------------|----------------------------------------|
-| `main.py` | Maix 系列开发板 + 摄像头 + 其他硬件 |
-| `laser.py` | Maix 系列开发板 + 激光测距模块(I²C) + 摄像头 + 其他硬件) |
-
-> 💡 **注意:引脚复用风险**
-> Maix 开发板部分 GPIO 兼容多协议(如 Wi-Fi / I²C 复用 A15/A27)。
-> **Wi-Fi 初始化前禁止提前配置 I²C 引脚!**
-
-### ❗ 关键提示
-
-| 问题场景 | 后果 |
-|---------|------|
-| 提前初始化 I²C | Wi-Fi 初始化失败、OTA 中断、系统重启 |
-
-✅ **正确做法:**
-
-- **`main.py`(视觉版)&`laser.py`(激光版)**
- 使用wifi时启用下面代码,注释与WiFi复用的:
- ```python
- # 以下代码(如有,请启用):
- # pinmap.set_pin_function("A15", "I2C5_SCL")
- # pinmap.set_pin_function("A27", "I2C5_SDA")
- ```
-
-
-
-
-## 📡 网络通信协议(TCP / JSON)
-
-设备上电后自动连预设服务器,支持以下指令:
-
-```json
-{"data": {"cmd": N, "ssid": "...", "password": "..."}}
-```
-
-| `cmd` | 参数 | 功能说明 |
-|-------|---------------------|------------------------------|
-| 2 | — | 开启激光校准模式 |
-| 3 | — | 关闭激光 |
-| 4 | — | 查询电池电量 & 电压 |
-| 5 | `ssid`, `password` | 配置 Wi-Fi + 触发 OTA 升级 |
-| 6 | — | 返回当前 IP 地址 |
-| 7 | — | 已联网时,直接执行 OTA 下载 |
-
-### 示例交互
-
-▶️ 下发指令(服务器 → 设备):
-```json
-{"data": {"cmd": 6}}
-```
-
-◀️ 设备响应(设备 → 服务器):
-```json
-{"result": "current_ip", "ip": "192.168.1.105"}
-```
-
----
-
-## 🛠️ 部署步骤
-
-1. **选择版本**
- - 固定场景 / 低成本 → `main.py`
- - 高精度需求 → `laser.py`
-
-2. **烧录程序**
- - 将选定文件重命名为 `main.py`,或通过 MaixPy IDE 直接运行
-
-3. **首次配置 Wi-Fi**
- - 串口下发,或服务器推送 `cmd=5`:
- ```json
- {"data": {"cmd": 5, "ssid": "YourWiFi", "password": "12345678"}}
- ```
-
-4. **后续 OTA 升级**
- - 确保设备在线后,下发 `cmd=7` 即可触发 OTA
-
----
-
-## 📝 注意事项
-
-- 🔗 **OTA 地址**:由全局变量 `url` 定义,部署前务必修改为实际地址
-- 🧵 **线程安全**:通过 `update_thread_started` 标志防止 OTA 并发下载
-- ☀️ **视觉版**:光照敏感,建议在均匀光源环境使用
-- 📏 **激光版**:确认模块 I²C 地址(默认 `0x29`),避免长线干扰
-- 🌐 **网络操作**:均在子线程执行,主线程保持实时响应
-
-## 🔧 打包步骤(命令行)
-- 以t11的名称打包,或者修改代码升级路径
----
-> 文档版本:v1.2
-> 更新时间:2025-11-21
-> 维护人:ZZH
-```
-
diff --git a/S99archery b/S99archery
deleted file mode 100644
index e70c36c..0000000
--- a/S99archery
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/bin/sh
-# /etc/init.d/S99archery
-# 系统启动时处理致命错误恢复(仅处理无法启动的情况)
-# 注意:应用的启动由系统自动启动机制处理(通过 auto_start.txt)
-# 功能:
-# 1. 处理致命错误(无法启动)- 恢复 main.py
-# 2. 如果重启次数超过阈值,恢复 main.py 并重启系统
-
-APP_DIR="/maixapp/apps/t11"
-MAIN_PY="$APP_DIR/main.py"
-PENDING_FILE="$APP_DIR/ota_pending.json"
-BACKUP_BASE="$APP_DIR/backups"
-
-# 进入应用目录
-cd "$APP_DIR" || exit 0
-
-# 检查 pending 文件,如果存在且超过重启次数,恢复 main.py(处理致命错误)
-if [ -f "$PENDING_FILE" ]; then
- echo "[S99] 检测到 ota_pending.json,检查重启计数..."
-
- # 尝试从JSON中提取重启计数(使用grep简单提取)
- RESTART_COUNT=$(cat "$PENDING_FILE" 2>/dev/null | grep -o '"restart_count":[0-9]*' | grep -o '[0-9]*' || echo "0")
- MAX_RESTARTS=$(cat "$PENDING_FILE" 2>/dev/null | grep -o '"max_restarts":[0-9]*' | grep -o '[0-9]*' || echo "3")
-
- if [ -n "$RESTART_COUNT" ] && [ "$RESTART_COUNT" -ge "$MAX_RESTARTS" ]; then
- echo "[S99] 检测到重启次数 ($RESTART_COUNT) 超过阈值 ($MAX_RESTARTS),恢复 main.py..."
-
- # 尝试从JSON中提取备份目录
- BACKUP_DIR=$(cat "$PENDING_FILE" 2>/dev/null | grep -o '"backup_dir":"[^"]*"' | grep -o '/[^"]*' || echo "")
-
- if [ -n "$BACKUP_DIR" ] && [ -f "$BACKUP_DIR/main.py" ]; then
- # 使用指定的备份目录
- echo "[S99] 从备份目录恢复: $BACKUP_DIR/main.py"
- cp "$BACKUP_DIR/main.py" "$MAIN_PY" 2>/dev/null && echo "[S99] 已恢复 main.py"
- else
- # 查找最新的备份目录
- LATEST_BACKUP=$(ls -dt "$BACKUP_BASE"/backup_* 2>/dev/null | head -1)
- if [ -n "$LATEST_BACKUP" ] && [ -f "$LATEST_BACKUP/main.py" ]; then
- echo "[S99] 从最新备份恢复: $LATEST_BACKUP/main.py"
- cp "$LATEST_BACKUP/main.py" "$MAIN_PY" 2>/dev/null && echo "[S99] 已恢复 main.py"
- else
- # 如果没有备份目录,尝试使用 main.py.bak
- if [ -f "$APP_DIR/main.py.bak" ]; then
- echo "[S99] 从 main.py.bak 恢复"
- cp "$APP_DIR/main.py.bak" "$MAIN_PY" 2>/dev/null && echo "[S99] 已恢复 main.py"
- fi
- fi
- fi
-
- # 恢复后重置重启计数,避免循环恢复
- # 注意:不在这里删除 pending 文件,让 main.py 在心跳成功后删除
- # 但是重置重启计数,以便恢复后的版本可以重新开始计数
- python3 -c "
-import json, os
-try:
- pending_path = '$PENDING_FILE'
- if os.path.exists(pending_path):
- with open(pending_path, 'r', encoding='utf-8') as f:
- d = json.load(f)
- d['restart_count'] = 0 # 重置重启计数
- with open(pending_path, 'w', encoding='utf-8') as f:
- json.dump(d, f)
- print('[S99] 已重置重启计数为 0')
-except Exception as e:
- print(f'[S99] 重置重启计数失败: {e}')
-" 2>/dev/null || echo "[S99] 无法重置重启计数(可能需要Python支持)"
-
- echo "[S99] 已恢复 main.py,重启系统..."
- echo "[S99] 注意:pending 文件将在心跳成功后由 main.py 删除"
- sleep 2
- reboot
- exit 0
- fi
-fi
-
-# 不启动应用,让系统自动启动机制处理
-# 这个脚本只负责处理致命错误恢复
-exit 0
-
diff --git a/__pycache__/at_client.cpython-312.pyc b/__pycache__/at_client.cpython-312.pyc
deleted file mode 100644
index 70304c5..0000000
Binary files a/__pycache__/at_client.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/config.cpython-312.pyc b/__pycache__/config.cpython-312.pyc
deleted file mode 100644
index 2293549..0000000
Binary files a/__pycache__/config.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/hardware.cpython-312.pyc b/__pycache__/hardware.cpython-312.pyc
deleted file mode 100644
index bf54453..0000000
Binary files a/__pycache__/hardware.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/laser_manager.cpython-312.pyc b/__pycache__/laser_manager.cpython-312.pyc
deleted file mode 100644
index 8b340a5..0000000
Binary files a/__pycache__/laser_manager.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/logger_manager.cpython-312.pyc b/__pycache__/logger_manager.cpython-312.pyc
deleted file mode 100644
index 7b74d03..0000000
Binary files a/__pycache__/logger_manager.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/main.cpython-312.pyc b/__pycache__/main.cpython-312.pyc
deleted file mode 100644
index 151a0f4..0000000
Binary files a/__pycache__/main.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/network.cpython-312.pyc b/__pycache__/network.cpython-312.pyc
deleted file mode 100644
index d2ea7a2..0000000
Binary files a/__pycache__/network.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/power.cpython-312.pyc b/__pycache__/power.cpython-312.pyc
deleted file mode 100644
index a44af99..0000000
Binary files a/__pycache__/power.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/version.cpython-310.pyc b/__pycache__/version.cpython-310.pyc
deleted file mode 100644
index eecf161..0000000
Binary files a/__pycache__/version.cpython-310.pyc and /dev/null differ
diff --git a/__pycache__/version.cpython-312.pyc b/__pycache__/version.cpython-312.pyc
deleted file mode 100644
index 51dc910..0000000
Binary files a/__pycache__/version.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/vision.cpython-312.pyc b/__pycache__/vision.cpython-312.pyc
deleted file mode 100644
index 55f4dd1..0000000
Binary files a/__pycache__/vision.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/wifi.cpython-312.pyc b/__pycache__/wifi.cpython-312.pyc
deleted file mode 100644
index 4605320..0000000
Binary files a/__pycache__/wifi.cpython-312.pyc and /dev/null differ
diff --git a/__pycache__/wpa_supplicant_conf.cpython-312.pyc b/__pycache__/wpa_supplicant_conf.cpython-312.pyc
deleted file mode 100644
index 2b02460..0000000
Binary files a/__pycache__/wpa_supplicant_conf.cpython-312.pyc and /dev/null differ
diff --git a/adc.py b/adc.py
deleted file mode 100644
index 0584e63..0000000
--- a/adc.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from maix.peripheral import adc
-from maix import time
-
-a = adc.ADC(0, adc.RES_BIT_12)
-
-while True:
- # raw_data = a.read()
- # print(f"ADC raw data:{raw_data}")
- # if raw_data > 2450:
- # print(f"ADC raw data:{raw_data}")
- # elif raw_data < 2000:
- # print(f"ADC raw data:{raw_data}")
- time.sleep_ms(1)
-
- vol = int(a.read_vol() * 10) / 10
- print(f"ADC vol:{vol:.1f}, {time.time():.4f}")
diff --git a/aruco_detector.py b/aruco_detector.py
deleted file mode 100644
index 1b8b464..0000000
--- a/aruco_detector.py
+++ /dev/null
@@ -1,420 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-"""
-ArUco标记检测模块
-提供基于ArUco标记的靶心标定和激光点定位功能
-"""
-import cv2
-import numpy as np
-import math
-import config
-from logger_manager import logger_manager
-
-
-class ArUcoDetector:
- """ArUco标记检测器"""
-
- def __init__(self):
- self.logger = logger_manager.logger
- # 创建ArUco字典和检测器参数
- self.aruco_dict = cv2.aruco.getPredefinedDictionary(config.ARUCO_DICT_TYPE)
- self.detector_params = cv2.aruco.DetectorParameters()
-
- # 设置检测参数
- self.detector_params.minMarkerPerimeterRate = config.ARUCO_MIN_MARKER_PERIMETER_RATE
- self.detector_params.cornerRefinementMethod = config.ARUCO_CORNER_REFINEMENT_METHOD
-
- # 创建检测器
- self.detector = cv2.aruco.ArucoDetector(self.aruco_dict, self.detector_params)
-
- # 预定义靶纸上的标记位置(物理坐标,毫米)
- self.marker_positions_mm = config.ARUCO_MARKER_POSITIONS_MM
- self.marker_ids = config.ARUCO_MARKER_IDS
- self.marker_size_mm = config.ARUCO_MARKER_SIZE_MM
- self.target_paper_size_mm = config.TARGET_PAPER_SIZE_MM
-
- # 靶心偏移(相对于靶纸中心)
- self.target_center_offset_mm = config.TARGET_CENTER_OFFSET_MM
-
- if self.logger:
- self.logger.info(f"[ARUCO] ArUco检测器初始化完成,字典类型: {config.ARUCO_DICT_TYPE}")
-
- def detect_markers(self, frame):
- """
- 检测图像中的ArUco标记
-
- Args:
- frame: MaixPy图像帧对象
-
- Returns:
- (corners, ids, rejected) - 检测到的标记角点、ID列表、被拒绝的候选
- 如果检测失败返回 (None, None, None)
- """
- try:
- # 转换为OpenCV格式
- from maix import image
- img_cv = image.image2cv(frame, False, False)
-
- # 转换为灰度图(ArUco检测需要)
- if len(img_cv.shape) == 3:
- gray = cv2.cvtColor(img_cv, cv2.COLOR_RGB2GRAY)
- else:
- gray = img_cv
-
- # 检测标记
- corners, ids, rejected = self.detector.detectMarkers(gray)
-
- if self.logger and ids is not None:
- self.logger.debug(f"[ARUCO] 检测到 {len(ids)} 个标记: {ids.flatten().tolist()}")
-
- return corners, ids, rejected
-
- except Exception as e:
- if self.logger:
- self.logger.error(f"[ARUCO] 标记检测失败: {e}")
- return None, None, None
-
- def get_target_center_from_markers(self, corners, ids):
- """
- 从检测到的ArUco标记计算靶心位置
-
- Args:
- corners: 标记角点列表
- ids: 标记ID列表
-
- Returns:
- (center_x, center_y, radius, ellipse_params) 或 (None, None, None, None)
- center_x, center_y: 靶心像素坐标
- radius: 估计的靶心半径(像素)
- ellipse_params: 椭圆参数用于透视校正
- """
- if ids is None or len(ids) < 3:
- if self.logger:
- self.logger.debug(f"[ARUCO] 检测到的标记数量不足: {len(ids) if ids is not None else 0} < 3")
- return None, None, None, None
-
- try:
- # 将ID转换为列表便于查找
- detected_ids = ids.flatten().tolist()
-
- # 收集检测到的标记中心点和对应的物理坐标
- image_points = [] # 图像坐标 (像素)
- object_points = [] # 物理坐标 (毫米)
- marker_centers = {} # 存储每个标记的中心
-
- for i, marker_id in enumerate(detected_ids):
- if marker_id not in self.marker_ids:
- continue
-
- # 计算标记中心(四个角的平均值)
- corner = corners[i][0] # shape: (4, 2)
- center_x = np.mean(corner[:, 0])
- center_y = np.mean(corner[:, 1])
- marker_centers[marker_id] = (center_x, center_y)
-
- # 添加到点列表
- image_points.append([center_x, center_y])
- object_points.append(self.marker_positions_mm[marker_id])
-
- if len(image_points) < 3:
- if self.logger:
- self.logger.debug(f"[ARUCO] 有效标记数量不足: {len(image_points)} < 3")
- return None, None, None, None
-
- # 转换为numpy数组
- image_points = np.array(image_points, dtype=np.float32)
- object_points = np.array(object_points, dtype=np.float32)
-
- # 计算单应性矩阵(Homography)
- # 这建立了物理坐标到图像坐标的映射
- H, status = cv2.findHomography(object_points, image_points, cv2.RANSAC, 5.0)
-
- if H is None:
- if self.logger:
- self.logger.warning("[ARUCO] 无法计算单应性矩阵")
- return None, None, None, None
-
- # 计算靶心在图像中的位置
- # 靶心物理坐标 = 靶纸中心 + 偏移
- target_center_mm = np.array([[self.target_center_offset_mm[0],
- self.target_center_offset_mm[1]]], dtype=np.float32)
- target_center_mm = target_center_mm.reshape(-1, 1, 2)
-
- # 使用单应性矩阵投影到图像坐标
- target_center_img = cv2.perspectiveTransform(target_center_mm, H)
- center_x = target_center_img[0][0][0]
- center_y = target_center_img[0][0][1]
-
- # 计算靶心半径(像素)
- # 使用已知物理距离和像素距离的比例
- # 选择两个标记计算比例尺
- if len(marker_centers) >= 2:
- # 使用对角线上的标记计算比例尺
- if 0 in marker_centers and 2 in marker_centers:
- p1_img = np.array(marker_centers[0])
- p2_img = np.array(marker_centers[2])
- p1_mm = np.array(self.marker_positions_mm[0])
- p2_mm = np.array(self.marker_positions_mm[2])
- elif 1 in marker_centers and 3 in marker_centers:
- p1_img = np.array(marker_centers[1])
- p2_img = np.array(marker_centers[3])
- p1_mm = np.array(self.marker_positions_mm[1])
- p2_mm = np.array(self.marker_positions_mm[3])
- else:
- # 使用任意两个标记
- keys = list(marker_centers.keys())
- p1_img = np.array(marker_centers[keys[0]])
- p2_img = np.array(marker_centers[keys[1]])
- p1_mm = np.array(self.marker_positions_mm[keys[0]])
- p2_mm = np.array(self.marker_positions_mm[keys[1]])
-
- pixel_distance = np.linalg.norm(p1_img - p2_img)
- mm_distance = np.linalg.norm(p1_mm - p2_mm)
-
- if mm_distance > 0:
- pixels_per_mm = pixel_distance / mm_distance
- # 标准靶心半径:10环半径约1.22cm = 12.2mm
- # 但这里我们返回一个估计值,实际环数计算在laser_manager中
- radius_mm = 122.0 # 整个靶纸的半径约200mm,但靶心区域较小
- radius = int(radius_mm * pixels_per_mm)
- else:
- radius = 100 # 默认值
- else:
- radius = 100 # 默认值
-
- # 计算椭圆参数(用于透视校正)
- # 从单应性矩阵可以推导出透视变形
- ellipse_params = self._compute_ellipse_params(H, center_x, center_y)
-
- if self.logger:
- self.logger.info(f"[ARUCO] 靶心计算成功: 中心=({center_x:.1f}, {center_y:.1f}), "
- f"半径={radius}px, 检测到{len(marker_centers)}个标记")
-
- return (int(center_x), int(center_y)), radius, "aruco", ellipse_params
-
- except Exception as e:
- if self.logger:
- self.logger.error(f"[ARUCO] 计算靶心失败: {e}")
- import traceback
- self.logger.error(traceback.format_exc())
- return None, None, None, None
-
- def _compute_ellipse_params(self, H, center_x, center_y):
- """
- 从单应性矩阵计算椭圆参数,用于透视校正
-
- Args:
- H: 单应性矩阵 (3x3)
- center_x, center_y: 靶心图像坐标
-
- Returns:
- ellipse_params: ((center_x, center_y), (width, height), angle)
- """
- try:
- # 在物理坐标系中画一个圆,投影到图像中看变成什么形状
- # 物理圆:半径10mm
- r_mm = 10.0
- angles = np.linspace(0, 2*np.pi, 16)
- circle_mm = np.array([[self.target_center_offset_mm[0] + r_mm * np.cos(a),
- self.target_center_offset_mm[1] + r_mm * np.sin(a)]
- for a in angles], dtype=np.float32)
- circle_mm = circle_mm.reshape(-1, 1, 2)
-
- # 投影到图像
- circle_img = cv2.perspectiveTransform(circle_mm, H)
- circle_img = circle_img.reshape(-1, 2)
-
- # 拟合椭圆
- if len(circle_img) >= 5:
- ellipse = cv2.fitEllipse(circle_img.astype(np.float32))
- return ellipse
- else:
- # 从单应性矩阵近似估计
- # 提取缩放和旋转
- # H = K * [R|t] 的近似
- # 这里简化处理:假设没有严重变形
- scale_x = np.linalg.norm(H[0, :2])
- scale_y = np.linalg.norm(H[1, :2])
- avg_scale = (scale_x + scale_y) / 2
-
- width = r_mm * 2 * scale_x
- height = r_mm * 2 * scale_y
- angle = np.degrees(np.arctan2(H[1, 0], H[0, 0]))
-
- return ((center_x, center_y), (width, height), angle)
-
- except Exception as e:
- if self.logger:
- self.logger.debug(f"[ARUCO] 计算椭圆参数失败: {e}")
- return None
-
- def transform_laser_point(self, laser_point, corners, ids):
- """
- 将激光点从图像坐标转换到物理坐标(毫米),再计算相对于靶心的偏移
-
- Args:
- laser_point: (x, y) 激光点在图像中的坐标
- corners: 检测到的标记角点
- ids: 检测到的标记ID
-
- Returns:
- (dx_mm, dy_mm) 激光点相对于靶心的偏移(毫米),或 (None, None)
- """
- if laser_point is None or ids is None or len(ids) < 3:
- return None, None
-
- try:
- # 重新计算单应性矩阵(可以优化为缓存)
- detected_ids = ids.flatten().tolist()
- image_points = []
- object_points = []
-
- for i, marker_id in enumerate(detected_ids):
- if marker_id not in self.marker_ids:
- continue
- corner = corners[i][0]
- center_x = np.mean(corner[:, 0])
- center_y = np.mean(corner[:, 1])
- image_points.append([center_x, center_y])
- object_points.append(self.marker_positions_mm[marker_id])
-
- if len(image_points) < 3:
- return None, None
-
- image_points = np.array(image_points, dtype=np.float32)
- object_points = np.array(object_points, dtype=np.float32)
-
- H, _ = cv2.findHomography(object_points, image_points, cv2.RANSAC, 5.0)
- if H is None:
- return None, None
-
- # 求逆矩阵,将图像坐标转换到物理坐标
- H_inv = np.linalg.inv(H)
-
- laser_img = np.array([[laser_point[0], laser_point[1]]], dtype=np.float32)
- laser_img = laser_img.reshape(-1, 1, 2)
-
- laser_mm = cv2.perspectiveTransform(laser_img, H_inv)
- laser_x_mm = laser_mm[0][0][0]
- laser_y_mm = laser_mm[0][0][1]
-
- # 计算相对于靶心的偏移
- # 注意:Y轴方向可能需要翻转(图像Y向下,物理Y通常向上)
- dx_mm = laser_x_mm - self.target_center_offset_mm[0]
- dy_mm = -(laser_y_mm - self.target_center_offset_mm[1]) # 翻转Y轴
-
- if self.logger:
- self.logger.debug(f"[ARUCO] 激光点转换: 图像({laser_point[0]:.1f}, {laser_point[1]:.1f}) -> "
- f"物理({laser_x_mm:.1f}, {laser_y_mm:.1f}) -> "
- f"偏移({dx_mm:.1f}, {dy_mm:.1f})mm")
-
- return dx_mm, dy_mm
-
- except Exception as e:
- if self.logger:
- self.logger.error(f"[ARUCO] 激光点转换失败: {e}")
- return None, None
-
- def draw_debug_info(self, frame, corners, ids, target_center=None, laser_point=None):
- """
- 在图像上绘制调试信息
-
- Args:
- frame: MaixPy图像帧
- corners: 标记角点
- ids: 标记ID
- target_center: 计算的靶心位置
- laser_point: 激光点位置
-
- Returns:
- 绘制后的图像
- """
- try:
- from maix import image
- img_cv = image.image2cv(frame, False, False).copy()
-
- # 绘制检测到的标记
- if ids is not None:
- cv2.aruco.drawDetectedMarkers(img_cv, corners, ids)
-
- # 绘制标记ID和中心
- for i, marker_id in enumerate(ids.flatten()):
- corner = corners[i][0]
- center_x = int(np.mean(corner[:, 0]))
- center_y = int(np.mean(corner[:, 1]))
-
- # 绘制中心点
- cv2.circle(img_cv, (center_x, center_y), 5, (0, 255, 0), -1)
-
- # 绘制ID
- cv2.putText(img_cv, f"ID:{marker_id}",
- (center_x + 10, center_y - 10),
- cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
-
- # 绘制靶心
- if target_center:
- cv2.circle(img_cv, target_center, 8, (255, 0, 0), -1)
- cv2.circle(img_cv, target_center, 50, (255, 0, 0), 2)
- cv2.putText(img_cv, "TARGET", (target_center[0] + 15, target_center[1] - 15),
- cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
-
- # 绘制激光点
- if laser_point:
- cv2.circle(img_cv, (int(laser_point[0]), int(laser_point[1])), 6, (0, 0, 255), -1)
- cv2.putText(img_cv, "LASER", (int(laser_point[0]) + 10, int(laser_point[1]) - 10),
- cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
-
- # 转换回MaixPy图像
- return image.cv2image(img_cv, False, False)
-
- except Exception as e:
- if self.logger:
- self.logger.error(f"[ARUCO] 绘制调试信息失败: {e}")
- return frame
-
-
-# 创建全局单例实例
-aruco_detector = ArUcoDetector()
-
-
-def detect_target_with_aruco(frame, laser_point=None):
- """
- 使用ArUco标记检测靶心的便捷函数
-
- Args:
- frame: MaixPy图像帧
- laser_point: 激光点坐标(可选)
-
- Returns:
- (result_img, center, radius, method, best_radius1, ellipse_params)
- 与detect_circle_v3保持相同的返回格式
- """
- detector = aruco_detector
-
- # 检测ArUco标记
- corners, ids, rejected = detector.detect_markers(frame)
-
- # 计算靶心
- center, radius, method, ellipse_params = detector.get_target_center_from_markers(corners, ids)
-
- # 绘制调试信息
- result_img = detector.draw_debug_info(frame, corners, ids, center, laser_point)
-
- # 返回与detect_circle_v3相同的格式
- # best_radius1用于距离估算,这里用radius代替
- return result_img, center, radius, method, radius, ellipse_params
-
-
-def compute_laser_offset_aruco(laser_point, corners, ids):
- """
- 使用ArUco计算激光点相对于靶心的偏移(毫米)
-
- Args:
- laser_point: (x, y) 激光点图像坐标
- corners: ArUco标记角点
- ids: ArUco标记ID
-
- Returns:
- (dx_mm, dy_mm) 偏移量(毫米),或 (None, None)
- """
- return aruco_detector.transform_laser_point(laser_point, corners, ids)
diff --git a/cpp_ext/CMakeLists.txt b/cpp_ext/CMakeLists.txt
deleted file mode 100644
index 476d84d..0000000
--- a/cpp_ext/CMakeLists.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-cmake_minimum_required(VERSION 3.16)
-project(archery_netcore CXX)
-
-set(CMAKE_SYSTEM_NAME Linux)
-set(CMAKE_SYSTEM_PROCESSOR riscv64)
-set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_POSITION_INDEPENDENT_CODE ON)
-
-if(NOT DEFINED PY_INCLUDE_DIR)
- message(FATAL_ERROR "PY_INCLUDE_DIR not set")
-endif()
-if(NOT DEFINED PY_LIB)
- message(FATAL_ERROR "PY_LIB not set")
-endif()
-if(NOT DEFINED PY_EXT_SUFFIX)
- message(FATAL_ERROR "PY_EXT_SUFFIX not set")
-endif()
-if(NOT DEFINED MAIXCDK_PATH)
- message(FATAL_ERROR "MAIXCDK_PATH not set (need components/3rd_party/pybind11)")
-endif()
-
-add_library(archery_netcore MODULE
- archery_netcore.cpp
- native_logger.cpp
- utils.cpp
- decrypt_ota_file.cpp
- msg_handler.cpp
- tcp_ssl_password.cpp
-)
-
-target_include_directories(archery_netcore PRIVATE
- "${PY_INCLUDE_DIR}"
- "${MAIXCDK_PATH}/components/3rd_party/pybind11/pybind11/include"
- "${MAIXCDK_PATH}/components/3rd_party/openssl/include"
- "${CMAKE_CURRENT_SOURCE_DIR}/third_party" # 添加 nlohmann/json 路径
-)
-
-# 尽量减少 .so 体积并增加逆向成本
-target_compile_options(archery_netcore PRIVATE
- -Os
- -ffunction-sections
- -fdata-sections
- -fvisibility=hidden
- -fvisibility-inlines-hidden
-)
-target_link_options(archery_netcore PRIVATE
- -Wl,--gc-sections
- -Wl,-s
-)
-
-set_target_properties(archery_netcore PROPERTIES
- PREFIX ""
- SUFFIX "${PY_EXT_SUFFIX}"
-)
-
-# OpenSSL (for AES-256-GCM decrypt)
-# 使用 MaixCDK 提供的 OpenSSL 库(在 so/maixcam 目录下)
-set(OPENSSL_LIB_DIR "${MAIXCDK_PATH}/components/3rd_party/openssl/so/maixcam")
-if(EXISTS "${OPENSSL_LIB_DIR}/libcrypto.so")
- target_link_directories(archery_netcore PRIVATE "${OPENSSL_LIB_DIR}")
- target_link_libraries(archery_netcore PRIVATE "${PY_LIB}" crypto ssl)
- message(STATUS "Using OpenSSL from MaixCDK: ${OPENSSL_LIB_DIR}")
-else()
- # Fallback: 尝试 find_package 或系统库
- find_package(OpenSSL QUIET)
- if(OpenSSL_FOUND)
- target_link_libraries(archery_netcore PRIVATE "${PY_LIB}" OpenSSL::Crypto OpenSSL::SSL)
- else()
- message(WARNING "OpenSSL not found in MaixCDK, trying system libraries (may fail)")
- target_link_libraries(archery_netcore PRIVATE "${PY_LIB}" crypto ssl)
- endif()
-endif()
\ No newline at end of file
diff --git a/cpp_ext/archery_netcore.cpp b/cpp_ext/archery_netcore.cpp
deleted file mode 100644
index 06162a6..0000000
--- a/cpp_ext/archery_netcore.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-#include
-#include // 支持 std::vector, std::map 等
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "msg_handler.hpp"
-#include "native_logger.hpp"
-#include "decrypt_ota_file.hpp"
-#include "utils.hpp"
-#include "tcp_ssl_password.hpp"
-
-namespace py = pybind11;
-using json = nlohmann::json;
-
-namespace {
- // 配置项
- const std::string _cfg_server_ip = "www.shelingxingqiu.com";
- const int _cfg_server_port = 50005;
- const std::string _cfg_device_id_file = "/device_key";
-
-
-}
-
-// 定义获取配置的函数
-py::dict get_config() {
- py::dict config;
- config["SERVER_IP"] = _cfg_server_ip;
- config["SERVER_PORT"] = _cfg_server_port;
- return config;
-}
-
-
-
-
-
-PYBIND11_MODULE(archery_netcore, m) {
- m.doc() = "Archery net core (native, pybind11).";
-
- // Optional: configure native logger from Python.
- // Default log file: /maixapp/apps/t11/netcore.log
- m.def("set_log_file", [](const std::string& path) { netcore::set_log_file(path); }, py::arg("path"));
- m.def("set_log_level", [](int level) {
- if (level < 0) level = 0;
- if (level > 3) level = 3;
- netcore::set_log_level(static_cast(level));
- }, py::arg("level"));
- m.def("log_test", [](const std::string& msg) {
- netcore::log_info(std::string("log_test: ") + msg);
- }, py::arg("msg"));
-
- m.def("make_packet", &netcore::make_packet,
- "Pack TCP packet: header (len+type+checksum) + JSON body",
- py::arg("msg_type"), py::arg("body_dict"));
-
- m.def("parse_packet", &netcore::parse_packet,
- "Parse TCP packet, return (msg_type, body_dict)");
-
- m.def("get_config", &get_config, "Get system configuration");
-
- m.def(
- "calculate_tcp_ssl_password",
- &netcore::calculate_tcp_ssl_password,
- "Calculate TCP SSL password: hex(md5(hex(md5(device_id)) + iccid))",
- py::arg("device_id"),
- py::arg("iccid")
- );
-
- m.def(
- "decrypt_ota_file",
- [](const std::string& input_path, const std::string& output_zip_path) {
- netcore::log_info(std::string("decrypt_ota_file in=") + input_path + " out=" + output_zip_path);
- return netcore::decrypt_ota_file_impl(input_path, output_zip_path);
- },
- py::arg("input_path"),
- py::arg("output_zip_path"),
- "Decrypt OTA encrypted file (MAGIC|nonce|ciphertext|tag) to plaintext zip."
- );
-
- // Minimal demo: return actions for inner_cmd=41 (manual trigger + ack)
- m.def("actions_for_inner_cmd", [](int inner_cmd) {
- py::list actions;
-
- if (inner_cmd == 41) {
- // 1) set manual trigger flag
- {
- py::dict a;
- a["type"] = "SET_FLAG";
- py::dict args;
- args["name"] = "manual_trigger_flag";
- args["value"] = true;
- a["args"] = args;
- actions.append(a);
- }
-
- // 2) enqueue trigger_ack
- {
- py::dict a;
- a["type"] = "ENQUEUE";
- py::dict args;
- args["msg_type"] = 2;
- args["high"] = false;
- py::dict body;
- body["result"] = "trigger_ack";
- args["body"] = body;
- a["args"] = args;
- actions.append(a);
- }
- }
-
- return actions;
- });
-}
\ No newline at end of file
diff --git a/cpp_ext/decrypt_ota_file.cpp b/cpp_ext/decrypt_ota_file.cpp
deleted file mode 100644
index 1b52e51..0000000
--- a/cpp_ext/decrypt_ota_file.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "native_logger.hpp"
-
-namespace netcore{
-
- // OTA AEAD format: MAGIC(7) | nonce(12) | ciphertext(N) | tag(16)
- constexpr const char* kOtaMagic = "AROTAE1";
- constexpr size_t kOtaMagicLen = 7;
- constexpr size_t kGcmNonceLen = 12;
- constexpr size_t kGcmTagLen = 16;
- constexpr size_t kHeaderLen = kOtaMagicLen + kGcmNonceLen;
- // 分块解密,避免整包读入导致 RAM 峰值约为「文件大小×2」(小内存设备易 OOM)
- constexpr size_t kDecryptChunk = 65536;
-
- static std::array ota_key_bytes() {
- static const std::array a = {
- 0x92,0x99,0x4d,0x06,0x6f,0xb6,0xa6,0x3d,0x85,0x08,0xbe,0x73,0x5e,0x73,0x4d,0x8a,
- 0x53,0x88,0xe6,0x99,0xfc,0x10,0x29,0xb9,0x16,0x9b,0xe7,0x0c,0x65,0x21,0x1c,0xce
- };
- static const std::array b = {
- 0xcf,0x60,0xa2,0xc2,0x32,0x7a,0x61,0xb0,0x4c,0x8e,0x8a,0x62,0x31,0xc7,0x82,0xff,
- 0xec,0xac,0xa1,0x04,0x2a,0x4d,0xaa,0xf2,0xb0,0x5b,0x39,0x2b,0xf4,0xb3,0xad,0xad
- };
- std::array k{};
- for (size_t i = 0; i < k.size(); i++) k[i] = static_cast(a[i] ^ b[i]);
- return k;
- }
-
- bool decrypt_ota_file_impl(const std::string& input_path, const std::string& output_zip_path) {
- std::ifstream ifs(input_path, std::ios::binary);
- if (!ifs) {
- netcore::log_error(std::string("decrypt_ota_file: open in failed: ") + input_path);
- return false;
- }
- ifs.seekg(0, std::ios::end);
- const std::streampos szp = ifs.tellg();
- if (szp <= 0) {
- netcore::log_error("decrypt_ota_file: empty input");
- return false;
- }
- const uint64_t file_size = static_cast(szp);
- const size_t min_len = kHeaderLen + kGcmTagLen + 1;
- if (file_size < min_len) {
- netcore::log_error("decrypt_ota_file: too short");
- return false;
- }
- const uint64_t ciphertext_len = file_size - kHeaderLen - kGcmTagLen;
-
- ifs.seekg(0, std::ios::beg);
- std::array header{};
- ifs.read(reinterpret_cast(header.data()), static_cast(kHeaderLen));
- if (ifs.gcount() != static_cast(kHeaderLen)) {
- netcore::log_error("decrypt_ota_file: read header failed");
- return false;
- }
- if (!std::equal(header.begin(), header.begin() + kOtaMagicLen,
- reinterpret_cast(kOtaMagic))) {
- netcore::log_error("decrypt_ota_file: bad magic");
- return false;
- }
- const uint8_t* nonce = header.data() + kOtaMagicLen;
-
- std::ofstream ofs(output_zip_path, std::ios::binary | std::ios::trunc);
- if (!ofs) {
- netcore::log_error(std::string("decrypt_ota_file: open out failed: ") + output_zip_path);
- return false;
- }
-
- EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
- if (!ctx) {
- netcore::log_error("decrypt_ota_file: EVP_CIPHER_CTX_new failed");
- return false;
- }
-
- bool ok = false;
- auto key = ota_key_bytes();
- std::vector chunk_in(kDecryptChunk);
- std::vector chunk_out(kDecryptChunk + EVP_MAX_BLOCK_LENGTH);
-
- do {
- if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) {
- netcore::log_error("decrypt_ota_file: DecryptInit failed");
- break;
- }
- if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, static_cast(kGcmNonceLen), nullptr)) {
- netcore::log_error("decrypt_ota_file: set ivlen failed");
- break;
- }
- if (1 != EVP_DecryptInit_ex(ctx, nullptr, nullptr, key.data(), nonce)) {
- netcore::log_error("decrypt_ota_file: set key/iv failed");
- break;
- }
-
- uint64_t remaining = ciphertext_len;
- while (remaining > 0) {
- const size_t n = static_cast(std::min(remaining, kDecryptChunk));
- ifs.read(reinterpret_cast(chunk_in.data()), static_cast(n));
- if (ifs.gcount() != static_cast(n)) {
- netcore::log_error("decrypt_ota_file: read ciphertext chunk failed");
- goto cleanup_ctx;
- }
- int outl = 0;
- if (1 != EVP_DecryptUpdate(ctx, chunk_out.data(), &outl,
- chunk_in.data(), static_cast(n))) {
- netcore::log_error("decrypt_ota_file: update failed");
- goto cleanup_ctx;
- }
- if (outl > 0) {
- ofs.write(reinterpret_cast(chunk_out.data()), outl);
- if (!ofs) {
- netcore::log_error("decrypt_ota_file: write plaintext failed");
- goto cleanup_ctx;
- }
- }
- remaining -= n;
- }
-
- std::array tag{};
- ifs.read(reinterpret_cast(tag.data()), static_cast(kGcmTagLen));
- if (ifs.gcount() != static_cast(kGcmTagLen)) {
- netcore::log_error("decrypt_ota_file: read tag failed");
- break;
- }
- if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, static_cast(kGcmTagLen), tag.data())) {
- netcore::log_error("decrypt_ota_file: set tag failed");
- break;
- }
-
- int outl2 = 0;
- if (1 != EVP_DecryptFinal_ex(ctx, chunk_out.data(), &outl2)) {
- netcore::log_error("decrypt_ota_file: final failed (auth tag mismatch?)");
- break;
- }
- if (outl2 > 0) {
- ofs.write(reinterpret_cast(chunk_out.data()), outl2);
- if (!ofs) {
- netcore::log_error("decrypt_ota_file: write final failed");
- break;
- }
- }
- ok = true;
- } while (false);
-
-cleanup_ctx:
- EVP_CIPHER_CTX_free(ctx);
- return ok;
- }
-} // namespace netcore
diff --git a/cpp_ext/decrypt_ota_file.hpp b/cpp_ext/decrypt_ota_file.hpp
deleted file mode 100644
index 7ea5815..0000000
--- a/cpp_ext/decrypt_ota_file.hpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-#include
-
-namespace netcore{
- bool decrypt_ota_file_impl(const std::string& input_path, const std::string& output_zip_path);
-}
\ No newline at end of file
diff --git a/cpp_ext/msg_handler.cpp b/cpp_ext/msg_handler.cpp
deleted file mode 100644
index d06d900..0000000
--- a/cpp_ext/msg_handler.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include "native_logger.hpp"
-#include "msg_handler.hpp"
-#include "utils.hpp"
-
-namespace py = pybind11;
-using json = nlohmann::json;
-
-namespace netcore {
- // 打包 TCP 数据包
- py::bytes make_packet(int msg_type, py::dict body_dict) {
- netcore::log_debug(std::string("make_packet msg_type=") + std::to_string(msg_type));
- // 1) 将 py::dict 转为 JSON 字符串
- json j = netcore::py_dict_to_json(body_dict);
- std::string body_str = j.dump();
-
- // 2) 计算 body_len 和 checksum
- uint32_t body_len = body_str.size();
- uint32_t checksum = body_len + msg_type;
-
- // 3) 打包头部(大端序)
- std::vector packet;
- packet.reserve(12 + body_len);
-
- // body_len (big-endian, 4 bytes)
- packet.push_back((body_len >> 24) & 0xFF);
- packet.push_back((body_len >> 16) & 0xFF);
- packet.push_back((body_len >> 8) & 0xFF);
- packet.push_back(body_len & 0xFF);
-
- // msg_type (big-endian, 4 bytes)
- packet.push_back((msg_type >> 24) & 0xFF);
- packet.push_back((msg_type >> 16) & 0xFF);
- packet.push_back((msg_type >> 8) & 0xFF);
- packet.push_back(msg_type & 0xFF);
-
- // checksum (big-endian, 4 bytes)
- packet.push_back((checksum >> 24) & 0xFF);
- packet.push_back((checksum >> 16) & 0xFF);
- packet.push_back((checksum >> 8) & 0xFF);
- packet.push_back(checksum & 0xFF);
-
- // 4) 追加 body
- packet.insert(packet.end(), body_str.begin(), body_str.end());
-
- netcore::log_debug(std::string("make_packet done bytes=") + std::to_string(packet.size()));
- return py::bytes(reinterpret_cast(packet.data()), packet.size());
- }
-
- // 解析 TCP 数据包
- py::tuple parse_packet(py::bytes data) {
- // 1) 转换为 bytes view
- py::buffer_info buf = py::buffer(data).request();
- if (buf.size < 12) {
- netcore::log_error(std::string("parse_packet too_short len=") + std::to_string(buf.size));
- return py::make_tuple(py::none(), py::none());
- }
-
- const uint8_t* ptr = static_cast(buf.ptr);
-
- // 2) 解析头部(大端序)
- uint32_t body_len = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
- uint32_t msg_type = (ptr[4] << 24) | (ptr[5] << 16) | (ptr[6] << 8) | ptr[7];
- uint32_t checksum = (ptr[8] << 24) | (ptr[9] << 16) | (ptr[10] << 8) | ptr[11];
-
- // 3) 校验 checksum(可选,你现有代码不强制校验)
- // if (checksum != (body_len + msg_type)) {
- // return py::make_tuple(py::none(), py::none());
- // }
-
- // 4) 检查长度
- uint32_t expected_len = 12 + body_len;
- if (buf.size < expected_len) {
- // 半包
- netcore::log_warn(std::string("parse_packet incomplete got=") + std::to_string(buf.size) +
- " expected=" + std::to_string(expected_len));
- return py::make_tuple(py::none(), py::none());
- }
-
- // 5) 防御性检查:如果 data 比预期长,说明可能有粘包
- // (只解析第一个包,忽略多余数据)
- if (buf.size > expected_len) {
- netcore::log_warn(std::string("parse_packet concat got=") + std::to_string(buf.size) +
- " expected=" + std::to_string(expected_len) +
- " body_len=" + std::to_string(body_len) +
- " msg_type=" + std::to_string(msg_type));
- }
-
- // 6) 提取 body 并解析 JSON
- std::string body_str(reinterpret_cast(ptr + 12), body_len);
-
- try {
- json j = json::parse(body_str);
- py::dict body_dict = netcore::json_to_py_dict(j);
- return py::make_tuple(py::int_(msg_type), body_dict);
- } catch (const json::parse_error& e) {
- // JSON 解析失败,返回 raw(兼容你现有的逻辑)
- netcore::log_error(std::string("parse_packet json_parse_error: ") + e.what());
- py::dict raw_dict;
- raw_dict["raw"] = body_str;
- return py::make_tuple(py::int_(msg_type), raw_dict);
- } catch (const std::exception& e) {
- netcore::log_error(std::string("parse_packet json_parse_error: ") + e.what());
- py::dict raw_dict;
- raw_dict["raw"] = body_str;
- return py::make_tuple(py::int_(msg_type), raw_dict);
- }
- }
-}
\ No newline at end of file
diff --git a/cpp_ext/msg_handler.hpp b/cpp_ext/msg_handler.hpp
deleted file mode 100644
index fcee18f..0000000
--- a/cpp_ext/msg_handler.hpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-
-#include
-#include // 支持 std::vector, std::map 等
-
-namespace py = pybind11;
-
-namespace netcore {
-
- // 打包 TCP 数据包
- py::bytes make_packet(int msg_type, py::dict body_dict);
- // 解包 TCP 数据包
- py::tuple parse_packet(py::bytes data);
-}
\ No newline at end of file
diff --git a/cpp_ext/native_logger.cpp b/cpp_ext/native_logger.cpp
deleted file mode 100644
index d62c98c..0000000
--- a/cpp_ext/native_logger.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-#include "native_logger.hpp"
-
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-namespace netcore {
-
-static std::mutex g_mu;
-static int g_fd = -1;
-static std::string g_path = "netcore.log";
-static LogLevel g_level = LogLevel::kDebug; //LogLevel::kInfo;
-
-static const char* level_name(LogLevel lvl) {
- switch (lvl) {
- case LogLevel::kError: return "E";
- case LogLevel::kWarn: return "W";
- case LogLevel::kInfo: return "I";
- case LogLevel::kDebug: return "D";
- default: return "?";
- }
-}
-
-static void ensure_open_locked() {
- if (g_path.empty()) return;
- if (g_fd >= 0) return;
- g_fd = ::open(g_path.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644);
-}
-
-void set_log_file(const std::string& path) {
- std::lock_guard lk(g_mu);
- g_path = path;
- if (g_fd >= 0) {
- ::close(g_fd);
- g_fd = -1;
- }
- ensure_open_locked();
-}
-
-void set_log_level(LogLevel level) {
- std::lock_guard lk(g_mu);
- g_level = level;
-}
-
-void log(LogLevel level, const std::string& msg) {
- std::lock_guard lk(g_mu);
- if (static_cast(level) > static_cast(g_level)) return;
- if (g_path.empty()) return;
-
- ensure_open_locked();
- if (g_fd < 0) {
- // Last resort: stderr (avoid any Python APIs)
- ::write(STDERR_FILENO, msg.c_str(), msg.size());
- ::write(STDERR_FILENO, "\n", 1);
- return;
- }
-
- // Timestamp: epoch milliseconds (simple and cheap)
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-// long long ms = (long long)ts.tv_sec * 1000LL + ts.tv_nsec / 1000000LL;
- // 1. 将秒数转换为本地时间结构体 struct tm
- struct tm *tm_info = localtime(&ts.tv_sec);
-
- // 2. 准备一个缓冲区来存储时间字符串
- char buffer[30];
-
- // 3. 格式化秒的部分
- // 格式: 年-月-日 时:分:秒
- strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
-
- // 4. 计算毫秒部分并追加到字符串中
- // ts.tv_nsec 是纳秒,除以 1,000,000 得到毫秒
- char ms_buffer[8];
- snprintf(ms_buffer, sizeof(ms_buffer), ".%03ld", ts.tv_nsec / 1000000);
-
- // Build one line to keep writes atomic-ish
- char head[256];
- int n = ::snprintf(head, sizeof(head), "[%s%s] [%s] ", buffer, ms_buffer, level_name(level));
- if (n < 0) n = 0;
-
- ::write(g_fd, head, (size_t)n);
- ::write(g_fd, msg.c_str(), msg.size());
- ::write(g_fd, "\n", 1);
-}
-
-void log_debug(const std::string& msg) { log(LogLevel::kDebug, msg); }
-void log_info (const std::string& msg) { log(LogLevel::kInfo, msg); }
-void log_warn (const std::string& msg) { log(LogLevel::kWarn, msg); }
-void log_error(const std::string& msg) { log(LogLevel::kError, msg); }
-
-} // namespace netcore
-
diff --git a/cpp_ext/native_logger.hpp b/cpp_ext/native_logger.hpp
deleted file mode 100644
index 673aba9..0000000
--- a/cpp_ext/native_logger.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include
-
-namespace netcore {
-
-enum class LogLevel : int {
- kError = 0,
- kWarn = 1,
- kInfo = 2,
- kDebug = 3,
-};
-
-// Set log file path. If empty, logging is disabled.
-void set_log_file(const std::string& path);
-
-// Set minimum log level to write (default: kInfo).
-void set_log_level(LogLevel level);
-
-// Log helpers (thread-safe, never calls into Python).
-void log(LogLevel level, const std::string& msg);
-void log_debug(const std::string& msg);
-void log_info(const std::string& msg);
-void log_warn(const std::string& msg);
-void log_error(const std::string& msg);
-
-} // namespace netcore
-
diff --git a/cpp_ext/tcp_ssl_password.cpp b/cpp_ext/tcp_ssl_password.cpp
deleted file mode 100644
index 525e9aa..0000000
--- a/cpp_ext/tcp_ssl_password.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "tcp_ssl_password.hpp"
-
-#include
-#include
-#include
-
-namespace netcore {
-
-static std::string md5_hex(const std::string& input) {
- MD5_CTX ctx;
- MD5_Init(&ctx);
- MD5_Update(&ctx, input.data(), input.size());
-
- unsigned char digest[MD5_DIGEST_LENGTH];
- MD5_Final(digest, &ctx);
-
- std::ostringstream oss;
- oss << std::hex << std::setfill('0');
- for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
- oss << std::setw(2) << static_cast(digest[i]);
- }
- return oss.str();
-}
-
-std::string calculate_tcp_ssl_password(const std::string& device_id, const std::string& iccid) {
- std::string md5_device_hex = md5_hex(device_id);
- if (!iccid.empty()) {
- md5_device_hex += iccid;
- }
- return md5_hex(md5_device_hex);
-}
-
-} // namespace netcore
diff --git a/cpp_ext/tcp_ssl_password.hpp b/cpp_ext/tcp_ssl_password.hpp
deleted file mode 100644
index 71ecbfd..0000000
--- a/cpp_ext/tcp_ssl_password.hpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-#include
-
-namespace netcore {
- std::string calculate_tcp_ssl_password(const std::string& device_id, const std::string& iccid);
-}
diff --git a/cpp_ext/third_party/nlohmann/json.hpp b/cpp_ext/third_party/nlohmann/json.hpp
deleted file mode 100644
index 8b72ea6..0000000
--- a/cpp_ext/third_party/nlohmann/json.hpp
+++ /dev/null
@@ -1,24765 +0,0 @@
-// __ _____ _____ _____
-// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.3
-// |_____|_____|_____|_|___| https://github.com/nlohmann/json
-//
-// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann
-// SPDX-License-Identifier: MIT
-
-/****************************************************************************\
- * Note on documentation: The source files contain links to the online *
- * documentation of the public API at https://json.nlohmann.me. This URL *
- * contains the most recent documentation and should also be applicable to *
- * previous versions; documentation for deprecated functions is not *
- * removed, but marked deprecated. See "Generate documentation" section in *
- * file docs/README.md. *
-\****************************************************************************/
-
-#ifndef INCLUDE_NLOHMANN_JSON_HPP_
-#define INCLUDE_NLOHMANN_JSON_HPP_
-
-#include // all_of, find, for_each
-#include // nullptr_t, ptrdiff_t, size_t
-#include // hash, less
-#include // initializer_list
-#ifndef JSON_NO_IO
- #include // istream, ostream
-#endif // JSON_NO_IO
-#include // random_access_iterator_tag
-#include // unique_ptr
-#include // string, stoi, to_string
-#include // declval, forward, move, pair, swap
-#include // vector
-
-// #include
-// __ _____ _____ _____
-// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.3
-// |_____|_____|_____|_|___| https://github.com/nlohmann/json
-//
-// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann
-// SPDX-License-Identifier: MIT
-
-
-
-#include
-
-// #include
-// __ _____ _____ _____
-// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.3
-// |_____|_____|_____|_|___| https://github.com/nlohmann/json
-//
-// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann
-// SPDX-License-Identifier: MIT
-
-
-
-// This file contains all macro definitions affecting or depending on the ABI
-
-#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
- #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
- #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3
- #warning "Already included a different version of the library!"
- #endif
- #endif
-#endif
-
-#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
-#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum)
-#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum)
-
-#ifndef JSON_DIAGNOSTICS
- #define JSON_DIAGNOSTICS 0
-#endif
-
-#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
- #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
-#endif
-
-#if JSON_DIAGNOSTICS
- #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
-#else
- #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
-#endif
-
-#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
- #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
-#else
- #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
-#endif
-
-#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
- #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
-#endif
-
-// Construct the namespace ABI tags component
-#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
-#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
- NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
-
-#define NLOHMANN_JSON_ABI_TAGS \
- NLOHMANN_JSON_ABI_TAGS_CONCAT( \
- NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
- NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
-
-// Construct the namespace version component
-#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
- _v ## major ## _ ## minor ## _ ## patch
-#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
- NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
-
-#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
-#define NLOHMANN_JSON_NAMESPACE_VERSION
-#else
-#define NLOHMANN_JSON_NAMESPACE_VERSION \
- NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
- NLOHMANN_JSON_VERSION_MINOR, \
- NLOHMANN_JSON_VERSION_PATCH)
-#endif
-
-// Combine namespace components
-#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
-#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
- NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
-
-#ifndef NLOHMANN_JSON_NAMESPACE
-#define NLOHMANN_JSON_NAMESPACE \
- nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
- NLOHMANN_JSON_ABI_TAGS, \
- NLOHMANN_JSON_NAMESPACE_VERSION)
-#endif
-
-#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
-#define NLOHMANN_JSON_NAMESPACE_BEGIN \
- namespace nlohmann \
- { \
- inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
- NLOHMANN_JSON_ABI_TAGS, \
- NLOHMANN_JSON_NAMESPACE_VERSION) \
- {
-#endif
-
-#ifndef NLOHMANN_JSON_NAMESPACE_END
-#define NLOHMANN_JSON_NAMESPACE_END \
- } /* namespace (inline namespace) NOLINT(readability/namespace) */ \
- } // namespace nlohmann
-#endif
-
-// #include
-// __ _____ _____ _____
-// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.3
-// |_____|_____|_____|_|___| https://github.com/nlohmann/json
-//
-// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann
-// SPDX-License-Identifier: MIT
-
-
-
-#include // transform
-#include // array
-#include // forward_list
-#include // inserter, front_inserter, end
-#include