Compare commits
6 Commits
541418fd60
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c754dff4ad | ||
|
|
47018fcd69 | ||
|
|
afa99f598b | ||
|
|
e90ea5154c | ||
|
|
b895ea819c | ||
|
|
1a1dac6b8f |
4
app.yaml
4
app.yaml
@@ -1,6 +1,6 @@
|
|||||||
id: t11
|
id: t11
|
||||||
name: t11
|
name: t11
|
||||||
version: 1.2.12
|
version: 2.14.1
|
||||||
author: t11
|
author: t11
|
||||||
icon: ''
|
icon: ''
|
||||||
desc: t11
|
desc: t11
|
||||||
@@ -19,8 +19,6 @@ files:
|
|||||||
- main.py
|
- main.py
|
||||||
- model_270139.cvimodel
|
- model_270139.cvimodel
|
||||||
- model_270139.mud
|
- model_270139.mud
|
||||||
- model_270820.cvimodel
|
|
||||||
- model_270820.mud
|
|
||||||
- network.py
|
- network.py
|
||||||
- ota_manager.py
|
- ota_manager.py
|
||||||
- power.py
|
- power.py
|
||||||
|
|||||||
Binary file not shown.
@@ -34,10 +34,10 @@ WIFI_QUALITY_RSSI_BAD_DBM = -80.0 # 低于此 dBm(更负更差)视为信号
|
|||||||
WIFI_QUALITY_USE_RSSI = True # 是否把 RSSI 纳入综合判定
|
WIFI_QUALITY_USE_RSSI = True # 是否把 RSSI 纳入综合判定
|
||||||
|
|
||||||
# WiFi 热点配网(手机连设备 AP,浏览器提交路由器 SSID/密码;仅 GET/POST,标准库 socket)
|
# WiFi 热点配网(手机连设备 AP,浏览器提交路由器 SSID/密码;仅 GET/POST,标准库 socket)
|
||||||
WIFI_CONFIG_AP_FALLBACK = True # # WiFi 配网失败时,是否退回热点模式,并等待重新配网
|
WIFI_CONFIG_AP_FALLBACK = False # # WiFi 配网失败时,是否退回热点模式,并等待重新配网
|
||||||
WIFI_AP_FALLBACK_WAIT_SEC = 5 # 等待5秒后再检测STA/4G
|
WIFI_AP_FALLBACK_WAIT_SEC = 5 # 等待5秒后再检测STA/4G
|
||||||
WIFI_CONFIG_AP_TIMEOUT = 5 # 热点模式超时时间(秒)
|
WIFI_CONFIG_AP_TIMEOUT = 5 # 热点模式超时时间(秒)
|
||||||
WIFI_CONFIG_AP_ENABLED = True # True=启动时开热点并起迷你 HTTP 配网服务
|
WIFI_CONFIG_AP_ENABLED = False # True=启动时开热点并起迷你 HTTP 配网服务
|
||||||
WIFI_CONFIG_AP_SSID = "ArcherySetup" # 设备发出的热点名称
|
WIFI_CONFIG_AP_SSID = "ArcherySetup" # 设备发出的热点名称
|
||||||
WIFI_CONFIG_AP_PASSWORD = "12345678" # 热点密码(WPA2 通常至少 8 位)
|
WIFI_CONFIG_AP_PASSWORD = "12345678" # 热点密码(WPA2 通常至少 8 位)
|
||||||
WIFI_CONFIG_HTTP_HOST = "0.0.0.0" # HTTP 监听地址
|
WIFI_CONFIG_HTTP_HOST = "0.0.0.0" # HTTP 监听地址
|
||||||
@@ -255,6 +255,10 @@ TRIANGLE_YOLO_REJECT_BAD_ROI = True
|
|||||||
TRIANGLE_CROP_ROI_MIN_SIDE_PX = 64
|
TRIANGLE_CROP_ROI_MIN_SIDE_PX = 64
|
||||||
# 射箭保存图 / 预览上绘制 YOLO 靶环 ROI 矩形 (x0,y0,x1,y1),核对是否裁准;不需要时改 False
|
# 射箭保存图 / 预览上绘制 YOLO 靶环 ROI 矩形 (x0,y0,x1,y1),核对是否裁准;不需要时改 False
|
||||||
TRIANGLE_YOLO_DRAW_ROI_ON_SHOT = True
|
TRIANGLE_YOLO_DRAW_ROI_ON_SHOT = True
|
||||||
|
# 物方采样调试:以靶心为中心,取半径 15cm 的圆周样本点,用于黑/白颜色对比
|
||||||
|
TRIANGLE_SAMPLE_RADIUS_CM = 15.0
|
||||||
|
TRIANGLE_SAMPLE_ANGLES_DEG = (0, 90, 180, 270)
|
||||||
|
TRIANGLE_SAMPLE_PATCH_HALF_PX = 2
|
||||||
# 开机阶段预加载 YOLO detector;detect 使用 dual_buff=False,避免返回上一帧结果。
|
# 开机阶段预加载 YOLO detector;detect 使用 dual_buff=False,避免返回上一帧结果。
|
||||||
TRIANGLE_YOLO_PRELOAD_ON_BOOT = True
|
TRIANGLE_YOLO_PRELOAD_ON_BOOT = True
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
#include <pybind11/pybind11.h>
|
|
||||||
#include <pybind11/stl.h> // 支持 std::vector, std::map 等
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <openssl/evp.h>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <openssl/evp.h>
|
||||||
#include "native_logger.hpp"
|
#include "native_logger.hpp"
|
||||||
|
|
||||||
namespace netcore{
|
namespace netcore{
|
||||||
@@ -18,11 +15,11 @@ namespace netcore{
|
|||||||
constexpr size_t kOtaMagicLen = 7;
|
constexpr size_t kOtaMagicLen = 7;
|
||||||
constexpr size_t kGcmNonceLen = 12;
|
constexpr size_t kGcmNonceLen = 12;
|
||||||
constexpr size_t kGcmTagLen = 16;
|
constexpr size_t kGcmTagLen = 16;
|
||||||
|
constexpr size_t kHeaderLen = kOtaMagicLen + kGcmNonceLen;
|
||||||
|
// 分块解密,避免整包读入导致 RAM 峰值约为「文件大小×2」(小内存设备易 OOM)
|
||||||
|
constexpr size_t kDecryptChunk = 65536;
|
||||||
|
|
||||||
// 固定 32-byte AES-256-GCM key(提高被直接查看的成本;不是绝对安全)
|
|
||||||
// 注意:需要与打包端传入的 --aead-key-hex 保持一致。
|
|
||||||
static std::array<uint8_t, 32> ota_key_bytes() {
|
static std::array<uint8_t, 32> ota_key_bytes() {
|
||||||
// 简单拆分混淆:key = a XOR b
|
|
||||||
static const std::array<uint8_t, 32> a = {
|
static const std::array<uint8_t, 32> a = {
|
||||||
0x92,0x99,0x4d,0x06,0x6f,0xb6,0xa6,0x3d,0x85,0x08,0xbe,0x73,0x5e,0x73,0x4d,0x8a,
|
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
|
0x53,0x88,0xe6,0x99,0xfc,0x10,0x29,0xb9,0x16,0x9b,0xe7,0x0c,0x65,0x21,0x1c,0xce
|
||||||
@@ -36,56 +33,45 @@ namespace netcore{
|
|||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_file_all(const std::string& path, std::vector<uint8_t>& out) {
|
|
||||||
std::ifstream ifs(path, std::ios::binary);
|
|
||||||
if (!ifs) return false;
|
|
||||||
ifs.seekg(0, std::ios::end);
|
|
||||||
std::streampos size = ifs.tellg();
|
|
||||||
if (size <= 0) return false;
|
|
||||||
ifs.seekg(0, std::ios::beg);
|
|
||||||
out.resize(static_cast<size_t>(size));
|
|
||||||
if (!ifs.read(reinterpret_cast<char*>(out.data()), size)) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool write_file_all(const std::string& path, const uint8_t* data, size_t len) {
|
|
||||||
std::ofstream ofs(path, std::ios::binary | std::ios::trunc);
|
|
||||||
if (!ofs) return false;
|
|
||||||
ofs.write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(len));
|
|
||||||
return static_cast<bool>(ofs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool decrypt_ota_file_impl(const std::string& input_path, const std::string& output_zip_path) {
|
bool decrypt_ota_file_impl(const std::string& input_path, const std::string& output_zip_path) {
|
||||||
std::vector<uint8_t> in;
|
std::ifstream ifs(input_path, std::ios::binary);
|
||||||
if (!netcore::read_file_all(input_path, in)) {
|
if (!ifs) {
|
||||||
netcore::log_error(std::string("decrypt_ota_file: read failed: ") + input_path);
|
netcore::log_error(std::string("decrypt_ota_file: open in failed: ") + input_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
ifs.seekg(0, std::ios::end);
|
||||||
const size_t min_len = kOtaMagicLen + kGcmNonceLen + kGcmTagLen + 1;
|
const std::streampos szp = ifs.tellg();
|
||||||
if (in.size() < min_len) {
|
if (szp <= 0) {
|
||||||
|
netcore::log_error("decrypt_ota_file: empty input");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const uint64_t file_size = static_cast<uint64_t>(szp);
|
||||||
|
const size_t min_len = kHeaderLen + kGcmTagLen + 1;
|
||||||
|
if (file_size < min_len) {
|
||||||
netcore::log_error("decrypt_ota_file: too short");
|
netcore::log_error("decrypt_ota_file: too short");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!std::equal(in.begin(), in.begin() + kOtaMagicLen, reinterpret_cast<const uint8_t*>(kOtaMagic))) {
|
const uint64_t ciphertext_len = file_size - kHeaderLen - kGcmTagLen;
|
||||||
|
|
||||||
|
ifs.seekg(0, std::ios::beg);
|
||||||
|
std::array<uint8_t, kHeaderLen> header{};
|
||||||
|
ifs.read(reinterpret_cast<char*>(header.data()), static_cast<std::streamsize>(kHeaderLen));
|
||||||
|
if (ifs.gcount() != static_cast<std::streamsize>(kHeaderLen)) {
|
||||||
|
netcore::log_error("decrypt_ota_file: read header failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!std::equal(header.begin(), header.begin() + kOtaMagicLen,
|
||||||
|
reinterpret_cast<const uint8_t*>(kOtaMagic))) {
|
||||||
netcore::log_error("decrypt_ota_file: bad magic");
|
netcore::log_error("decrypt_ota_file: bad magic");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const uint8_t* nonce = header.data() + kOtaMagicLen;
|
||||||
|
|
||||||
const uint8_t* nonce = in.data() + kOtaMagicLen;
|
std::ofstream ofs(output_zip_path, std::ios::binary | std::ios::trunc);
|
||||||
const uint8_t* ct_and_tag = in.data() + kOtaMagicLen + kGcmNonceLen;
|
if (!ofs) {
|
||||||
const size_t ct_and_tag_len = in.size() - (kOtaMagicLen + kGcmNonceLen);
|
netcore::log_error(std::string("decrypt_ota_file: open out failed: ") + output_zip_path);
|
||||||
if (ct_and_tag_len <= kGcmTagLen) {
|
|
||||||
netcore::log_error("decrypt_ota_file: no ciphertext");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const size_t ciphertext_len = ct_and_tag_len - kGcmTagLen;
|
|
||||||
const uint8_t* ciphertext = ct_and_tag;
|
|
||||||
const uint8_t* tag = ct_and_tag + ciphertext_len;
|
|
||||||
|
|
||||||
std::vector<uint8_t> plain(ciphertext_len);
|
|
||||||
int out_len1 = 0;
|
|
||||||
int out_len2 = 0;
|
|
||||||
|
|
||||||
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
@@ -95,6 +81,8 @@ namespace netcore{
|
|||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
auto key = ota_key_bytes();
|
auto key = ota_key_bytes();
|
||||||
|
std::vector<uint8_t> chunk_in(kDecryptChunk);
|
||||||
|
std::vector<uint8_t> chunk_out(kDecryptChunk + EVP_MAX_BLOCK_LENGTH);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) {
|
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) {
|
||||||
@@ -109,27 +97,59 @@ namespace netcore{
|
|||||||
netcore::log_error("decrypt_ota_file: set key/iv failed");
|
netcore::log_error("decrypt_ota_file: set key/iv failed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (1 != EVP_DecryptUpdate(ctx, plain.data(), &out_len1, ciphertext, static_cast<int>(ciphertext_len))) {
|
|
||||||
|
uint64_t remaining = ciphertext_len;
|
||||||
|
while (remaining > 0) {
|
||||||
|
const size_t n = static_cast<size_t>(std::min<uint64_t>(remaining, kDecryptChunk));
|
||||||
|
ifs.read(reinterpret_cast<char*>(chunk_in.data()), static_cast<std::streamsize>(n));
|
||||||
|
if (ifs.gcount() != static_cast<std::streamsize>(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<int>(n))) {
|
||||||
netcore::log_error("decrypt_ota_file: update failed");
|
netcore::log_error("decrypt_ota_file: update failed");
|
||||||
|
goto cleanup_ctx;
|
||||||
|
}
|
||||||
|
if (outl > 0) {
|
||||||
|
ofs.write(reinterpret_cast<const char*>(chunk_out.data()), outl);
|
||||||
|
if (!ofs) {
|
||||||
|
netcore::log_error("decrypt_ota_file: write plaintext failed");
|
||||||
|
goto cleanup_ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remaining -= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<uint8_t, kGcmTagLen> tag{};
|
||||||
|
ifs.read(reinterpret_cast<char*>(tag.data()), static_cast<std::streamsize>(kGcmTagLen));
|
||||||
|
if (ifs.gcount() != static_cast<std::streamsize>(kGcmTagLen)) {
|
||||||
|
netcore::log_error("decrypt_ota_file: read tag failed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, static_cast<int>(kGcmTagLen), const_cast<uint8_t*>(tag))) {
|
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, static_cast<int>(kGcmTagLen), tag.data())) {
|
||||||
netcore::log_error("decrypt_ota_file: set tag failed");
|
netcore::log_error("decrypt_ota_file: set tag failed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (1 != EVP_DecryptFinal_ex(ctx, plain.data() + out_len1, &out_len2)) {
|
|
||||||
|
int outl2 = 0;
|
||||||
|
if (1 != EVP_DecryptFinal_ex(ctx, chunk_out.data(), &outl2)) {
|
||||||
netcore::log_error("decrypt_ota_file: final failed (auth tag mismatch?)");
|
netcore::log_error("decrypt_ota_file: final failed (auth tag mismatch?)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const size_t plain_len = static_cast<size_t>(out_len1 + out_len2);
|
if (outl2 > 0) {
|
||||||
if (!netcore::write_file_all(output_zip_path, plain.data(), plain_len)) {
|
ofs.write(reinterpret_cast<const char*>(chunk_out.data()), outl2);
|
||||||
netcore::log_error(std::string("decrypt_ota_file: write failed: ") + output_zip_path);
|
if (!ofs) {
|
||||||
|
netcore::log_error("decrypt_ota_file: write final failed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ok = true;
|
ok = true;
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
|
cleanup_ctx:
|
||||||
EVP_CIPHER_CTX_free(ctx);
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
}
|
} // namespace netcore
|
||||||
|
|||||||
33
cpp_ext/tcp_ssl_password.cpp
Normal file
33
cpp_ext/tcp_ssl_password.cpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include "tcp_ssl_password.hpp"
|
||||||
|
|
||||||
|
#include <openssl/md5.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
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<unsigned int>(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
|
||||||
7
cpp_ext/tcp_ssl_password.hpp
Normal file
7
cpp_ext/tcp_ssl_password.hpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace netcore {
|
||||||
|
std::string calculate_tcp_ssl_password(const std::string& device_id, const std::string& iccid);
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
|
|
||||||
1. CPP构建命令:
|
1. CPP构建命令:在docker环境下执行以下命令
|
||||||
|
|
||||||
cd /mnt/d/code/archery/cpp_ext
|
cd /data/cpp_ext
|
||||||
rm -rf build && mkdir build && cd build
|
rm -rf build && mkdir build && cd build
|
||||||
|
|
||||||
TOOLCHAIN_BIN=/mnt/d/code/MaixCDK/dl/extracted/toolchains/maixcam/host-tools/gcc/riscv64-linux-musl-x86_64/bin
|
TOOLCHAIN_BIN=/data/MaixCDK-main/dl/extracted/toolchains/maixcam/host-tools/gcc/riscv64-linux-musl-x86_64/bin
|
||||||
PYDEV=/mnt/d/code/shooting/python3_lib_maixcam_musl_3.11.6
|
PYDEV=/data/python3_lib_maixcam_musl_3.11.6
|
||||||
MAIXCDK=/mnt/d/code/MaixCDK
|
MAIXCDK=/data/MaixCDK-main
|
||||||
|
|
||||||
cmake .. -G Ninja \
|
cmake .. -G Ninja \
|
||||||
-DCMAKE_C_COMPILER="${TOOLCHAIN_BIN}/riscv64-unknown-linux-musl-gcc" \
|
-DCMAKE_C_COMPILER="${TOOLCHAIN_BIN}/riscv64-unknown-linux-musl-gcc" \
|
||||||
|
|||||||
@@ -770,12 +770,12 @@ class OTAManager:
|
|||||||
# 很多 ML307R 的 MHTTP 对 https 不稳定;对已知域名做降级
|
# 很多 ML307R 的 MHTTP 对 https 不稳定;对已知域名做降级
|
||||||
|
|
||||||
if isinstance(url, str) and url.startswith("https://static.shelingxingqiu.com/"):
|
if isinstance(url, str) and url.startswith("https://static.shelingxingqiu.com/"):
|
||||||
base_url = "https://static.shelingxingqiu.com"
|
base_url = "http://static.shelingxingqiu.com"
|
||||||
# TODO:使用https,看看是否能成功
|
self._is_https = False
|
||||||
self._is_https = True
|
|
||||||
else:
|
else:
|
||||||
base_url = f"http://{host}"
|
base_url = f"http://{host}"
|
||||||
self._is_https = False
|
self._is_https = False
|
||||||
|
self.logger.info(f"base_url: {base_url}, self._is_https: {self._is_https}")
|
||||||
# logger removed - use self.logger instead
|
# logger removed - use self.logger instead
|
||||||
|
|
||||||
def _log(*a):
|
def _log(*a):
|
||||||
@@ -1160,8 +1160,8 @@ class OTAManager:
|
|||||||
self.logger.error(f"[OTA-4G][PWR] before_urc read_failed: {e}")
|
self.logger.error(f"[OTA-4G][PWR] before_urc read_failed: {e}")
|
||||||
|
|
||||||
t_dl0 = time.ticks_ms()
|
t_dl0 = time.ticks_ms()
|
||||||
success, msg = self.download_file_via_4g(ota_url, downloaded_filename, debug=False)
|
success, msg = self.download_file_via_4g(ota_url, downloaded_filename, debug=True)
|
||||||
t_dl_cost = time.ticks_diff(t_dl0, time.ticks_ms())
|
t_dl_cost = time.ticks_diff(time.ticks_ms(), t_dl0)
|
||||||
self.logger.info(f"[OTA-4G] {msg}")
|
self.logger.info(f"[OTA-4G] {msg}")
|
||||||
self.logger.info(f"[OTA-4G] download_cost_ms={t_dl_cost}")
|
self.logger.info(f"[OTA-4G] download_cost_ms={t_dl_cost}")
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
应用版本号
|
应用版本号
|
||||||
每次 OTA 更新时,只需要更新这个文件中的版本号
|
每次 OTA 更新时,只需要更新这个文件中的版本号
|
||||||
"""
|
"""
|
||||||
VERSION = '1.2.12'
|
VERSION = '2.14.1'
|
||||||
|
|
||||||
|
|
||||||
# 1.2.0 开始使用C++编译成.so,替换部分代码
|
# 1.2.0 开始使用C++编译成.so,替换部分代码
|
||||||
# 1.2.1 ota使用加密包
|
# 1.2.1 ota使用加密包
|
||||||
@@ -19,8 +20,8 @@ VERSION = '1.2.12'
|
|||||||
# 1.2.10 config formal
|
# 1.2.10 config formal
|
||||||
# 1.2.11 增加三角形的单应性算法,适配对应的靶纸
|
# 1.2.11 增加三角形的单应性算法,适配对应的靶纸
|
||||||
# 1.2.110 关掉了黑色三角形算法,只用于测试
|
# 1.2.110 关掉了黑色三角形算法,只用于测试
|
||||||
|
# 1.2.13 修改wifi连接
|
||||||
|
# 1.2.14 修改了icc登录部分
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user