实现通过cdc进行升级。
This commit is contained in:
parent
5009528f3a
commit
c6554704ac
@ -2,6 +2,7 @@
|
|||||||
#include "AsyncEvent.h"
|
#include "AsyncEvent.h"
|
||||||
#include "BoostLog.h"
|
#include "BoostLog.h"
|
||||||
#include "CategoryLogSinkBackend.h"
|
#include "CategoryLogSinkBackend.h"
|
||||||
|
#include "CdcUpdater.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
#include "DateTime.h"
|
#include "DateTime.h"
|
||||||
@ -300,6 +301,9 @@ void Application::onNewImageInfo(ModuleCommunication::MessageId messageId, uint3
|
|||||||
m_communication->requestEnrolledImage(0, ImageSliceSize);
|
m_communication->requestEnrolledImage(0, ImageSliceSize);
|
||||||
m_palmYImageBuffer.clear();
|
m_palmYImageBuffer.clear();
|
||||||
m_startUploadTime = system_clock::now();
|
m_startUploadTime = system_clock::now();
|
||||||
|
if (messageId == ModuleCommunication::Note) {
|
||||||
|
emit newStatusTip(Error, "活体未通过照片");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onNewImageSliceData(const std::vector<uint8_t> &data) {
|
void Application::onNewImageSliceData(const std::vector<uint8_t> &data) {
|
||||||
@ -312,6 +316,9 @@ void Application::onNewImageSliceData(const std::vector<uint8_t> &data) {
|
|||||||
} else {
|
} else {
|
||||||
auto username = m_palmUsername.toStdString();
|
auto username = m_palmUsername.toStdString();
|
||||||
auto way = (m_palmImageId == ModuleCommunication::VerifyExtended) ? "verify" : "enroll";
|
auto way = (m_palmImageId == ModuleCommunication::VerifyExtended) ? "verify" : "enroll";
|
||||||
|
if (m_palmImageId == ModuleCommunication::Note) {
|
||||||
|
way = "no_alive";
|
||||||
|
}
|
||||||
LOG(info) << "request finished, username: " << username
|
LOG(info) << "request finished, username: " << username
|
||||||
<< ", elapsed: " << duration_cast<milliseconds>(system_clock::now() - m_startUploadTime);
|
<< ", elapsed: " << duration_cast<milliseconds>(system_clock::now() - m_startUploadTime);
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
@ -382,3 +389,20 @@ void Application::onVerifyTimeout() {
|
|||||||
m_communication->verify(120);
|
m_communication->verify(120);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::startOta(const QString &path) {
|
||||||
|
LOG(info) << "start ota, ota path: " << path.toStdString();
|
||||||
|
m_updater = std::make_shared<CdcUpdater>();
|
||||||
|
connect(m_updater.get(), &CdcUpdater::deviceDiscovered, this, &Application::onCdcDeviceDiscovered);
|
||||||
|
connect(m_updater.get(), &CdcUpdater::updateFinished, this, &Application::updateFinished);
|
||||||
|
connect(m_updater.get(), &CdcUpdater::progressChanged, this, &Application::otaProgressChanged);
|
||||||
|
connect(m_updater.get(), &CdcUpdater::message, this, &Application::otaMessage);
|
||||||
|
|
||||||
|
m_communication->startOta();
|
||||||
|
m_updater->start(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::onCdcDeviceDiscovered(const QSerialPortInfo &info) {
|
||||||
|
auto status = m_updater->open(info);
|
||||||
|
LOG(info) << "open cdc port: " << info.portName().toStdString() << ", status: " << status;
|
||||||
|
}
|
||||||
|
@ -13,6 +13,7 @@ class Database;
|
|||||||
class VideoPlayer;
|
class VideoPlayer;
|
||||||
class VideoFrameProvider;
|
class VideoFrameProvider;
|
||||||
class QTimer;
|
class QTimer;
|
||||||
|
class CdcUpdater;
|
||||||
|
|
||||||
class Application : public QObject {
|
class Application : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -44,6 +45,7 @@ public:
|
|||||||
Q_INVOKABLE bool openUVC(const QString &deviceName);
|
Q_INVOKABLE bool openUVC(const QString &deviceName);
|
||||||
Q_INVOKABLE void close();
|
Q_INVOKABLE void close();
|
||||||
Q_INVOKABLE void closeUVC();
|
Q_INVOKABLE void closeUVC();
|
||||||
|
Q_INVOKABLE void startOta(const QString &path);
|
||||||
Q_INVOKABLE void verify(bool captureImage, uint8_t timeout);
|
Q_INVOKABLE void verify(bool captureImage, uint8_t timeout);
|
||||||
Q_INVOKABLE void enroll(const QString &username, bool persistence, uint8_t timeout);
|
Q_INVOKABLE void enroll(const QString &username, bool persistence, uint8_t timeout);
|
||||||
Q_INVOKABLE void enrollExtended(const QString &username, bool persistence, uint8_t timeout);
|
Q_INVOKABLE void enrollExtended(const QString &username, bool persistence, uint8_t timeout);
|
||||||
@ -69,6 +71,9 @@ signals:
|
|||||||
void newVideoFrame();
|
void newVideoFrame();
|
||||||
void newLog(const QString &log);
|
void newLog(const QString &log);
|
||||||
void newStatusTip(TipType type, const QString &tip);
|
void newStatusTip(TipType type, const QString &tip);
|
||||||
|
void updateFinished();
|
||||||
|
void otaMessage(const QString &text);
|
||||||
|
void otaProgressChanged(int32_t progress);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Application(int &argc, char **argv);
|
Application(int &argc, char **argv);
|
||||||
@ -80,10 +85,13 @@ protected:
|
|||||||
void onCommandStarted(ModuleCommunication::MessageId messageId);
|
void onCommandStarted(ModuleCommunication::MessageId messageId);
|
||||||
void onCommandFinished(ModuleCommunication::MessageId messageId, ModuleCommunication::MessageStatus status);
|
void onCommandFinished(ModuleCommunication::MessageId messageId, ModuleCommunication::MessageStatus status);
|
||||||
void onVerifyTimeout();
|
void onVerifyTimeout();
|
||||||
|
void onCdcDeviceDiscovered(const QSerialPortInfo &info);
|
||||||
|
void onUpdateFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<QGuiApplication> m_app;
|
std::shared_ptr<QGuiApplication> m_app;
|
||||||
std::shared_ptr<ModuleCommunication> m_communication;
|
std::shared_ptr<ModuleCommunication> m_communication;
|
||||||
|
std::shared_ptr<CdcUpdater> m_updater;
|
||||||
std::shared_ptr<Database> m_database;
|
std::shared_ptr<Database> m_database;
|
||||||
|
|
||||||
bool m_persistenceMode = true; // 模组持续识别
|
bool m_persistenceMode = true; // 模组持续识别
|
||||||
|
@ -29,6 +29,7 @@ qt_add_qml_module(Analyser
|
|||||||
qml/ConnectionItem.qml
|
qml/ConnectionItem.qml
|
||||||
qml/OperationItem.qml
|
qml/OperationItem.qml
|
||||||
qml/StatusTip.qml
|
qml/StatusTip.qml
|
||||||
|
qml/OtaPage.qml
|
||||||
RESOURCES
|
RESOURCES
|
||||||
resources/successfull.svg
|
resources/successfull.svg
|
||||||
resources/warning.svg
|
resources/warning.svg
|
||||||
|
@ -159,6 +159,11 @@ void ModuleCommunication::setDebugEnabled(bool enabled) {
|
|||||||
m_serialPort->write(reinterpret_cast<const char *>(frameData), frameSize);
|
m_serialPort->write(reinterpret_cast<const char *>(frameData), frameSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModuleCommunication::startOta() {
|
||||||
|
auto [frameData, frameSize] = generateFrame(StartOta);
|
||||||
|
m_serialPort->write(reinterpret_cast<const char *>(frameData), frameSize);
|
||||||
|
}
|
||||||
|
|
||||||
void ModuleCommunication::requestUniqueId() {
|
void ModuleCommunication::requestUniqueId() {
|
||||||
auto [frameData, frameSize] = generateFrame(GetUniqueID);
|
auto [frameData, frameSize] = generateFrame(GetUniqueID);
|
||||||
m_serialPort->write(reinterpret_cast<const char *>(frameData), frameSize);
|
m_serialPort->write(reinterpret_cast<const char *>(frameData), frameSize);
|
||||||
@ -346,6 +351,11 @@ void ModuleCommunication::processPackage(const uint8_t *data, uint16_t size) {
|
|||||||
LOG_CAT(info, GUI) << "模组日志: " << message;
|
LOG_CAT(info, GUI) << "模组日志: " << message;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case NoAliveImage: {
|
||||||
|
LOG(info) << "no alive image";
|
||||||
|
emit newImageInfo(Note, 600 * 800, nullptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
LOG(warning) << "unknown note command: 0x" << (static_cast<int>(noteId) & 0xff)
|
LOG(warning) << "unknown note command: 0x" << (static_cast<int>(noteId) & 0xff)
|
||||||
<< ", data: " << protocolDataFormatString(data, size);
|
<< ", data: " << protocolDataFormatString(data, size);
|
||||||
|
@ -28,6 +28,7 @@ public:
|
|||||||
GetImage = 0x1F, // 获取图片数据,通过VerifyExtended或EnrollExtended保存的
|
GetImage = 0x1F, // 获取图片数据,通过VerifyExtended或EnrollExtended保存的
|
||||||
DeleteUser = 0x20,
|
DeleteUser = 0x20,
|
||||||
DeleteAll = 0x21,
|
DeleteAll = 0x21,
|
||||||
|
StartOta = 0x40, // 模组进入boot模式进行ota升级
|
||||||
EnableDebug = 0x82,
|
EnableDebug = 0x82,
|
||||||
GetUniqueID = 0xAC,
|
GetUniqueID = 0xAC,
|
||||||
UploadImageInfo = 0xF6,
|
UploadImageInfo = 0xF6,
|
||||||
@ -41,6 +42,7 @@ public:
|
|||||||
PalmState = 0x01,
|
PalmState = 0x01,
|
||||||
UnknownError = 0x02,
|
UnknownError = 0x02,
|
||||||
DebugInfo = 0x55,
|
DebugInfo = 0x55,
|
||||||
|
NoAliveImage = 0x56,
|
||||||
};
|
};
|
||||||
enum MessageStatus : uint8_t {
|
enum MessageStatus : uint8_t {
|
||||||
Success = 0,
|
Success = 0,
|
||||||
@ -161,6 +163,7 @@ public:
|
|||||||
void uploadImageData(uint32_t offset, const uint8_t *data, uint32_t size);
|
void uploadImageData(uint32_t offset, const uint8_t *data, uint32_t size);
|
||||||
Q_INVOKABLE void requestCurrentStatus();
|
Q_INVOKABLE void requestCurrentStatus();
|
||||||
Q_INVOKABLE void setDebugEnabled(bool enabled);
|
Q_INVOKABLE void setDebugEnabled(bool enabled);
|
||||||
|
void startOta();
|
||||||
|
|
||||||
MessageId currentMessageId() const;
|
MessageId currentMessageId() const;
|
||||||
static std::string protocolDataFormatString(const uint8_t *data, int size);
|
static std::string protocolDataFormatString(const uint8_t *data, int size);
|
||||||
|
@ -70,7 +70,6 @@ void VideoPlayer::run() {
|
|||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
QImage image;
|
QImage image;
|
||||||
image.loadFromData(packet->data, packet->size);
|
image.loadFromData(packet->data, packet->size);
|
||||||
image.mirror(false, true);
|
|
||||||
if (!image.isNull() && m_callback) m_callback(image);
|
if (!image.isNull() && m_callback) m_callback(image);
|
||||||
} else {
|
} else {
|
||||||
char message[256] = {0};
|
char message[256] = {0};
|
||||||
|
@ -160,6 +160,10 @@ ColumnLayout {
|
|||||||
text: "ID查询"
|
text: "ID查询"
|
||||||
onClicked: App.module.requestUniqueId()
|
onClicked: App.module.requestUniqueId()
|
||||||
}
|
}
|
||||||
|
Button {
|
||||||
|
text: "OTA升级"
|
||||||
|
onClicked: loader.active = true
|
||||||
|
}
|
||||||
Row {
|
Row {
|
||||||
Text {
|
Text {
|
||||||
text: qsTr("日志")
|
text: qsTr("日志")
|
||||||
@ -171,4 +175,18 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: loader
|
||||||
|
source: "OtaPage.qml"
|
||||||
|
active: false
|
||||||
|
onLoaded: {
|
||||||
|
if (loader.item && loader.item.open) {
|
||||||
|
loader.item.open();
|
||||||
|
loader.item.onClose = ()=>{
|
||||||
|
loader.active= false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
115
Analyser/qml/OtaPage.qml
Normal file
115
Analyser/qml/OtaPage.qml
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
import Analyser
|
||||||
|
|
||||||
|
Popup {
|
||||||
|
id: root
|
||||||
|
parent: Overlay.overlay
|
||||||
|
anchors.centerIn: Overlay.overlay
|
||||||
|
width: 500
|
||||||
|
height: 200
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
property var onClose
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 10
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Button {
|
||||||
|
text: "关闭"
|
||||||
|
onClicked: root.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: 10
|
||||||
|
TextField {
|
||||||
|
id: otaFile
|
||||||
|
Layout.fillWidth: true
|
||||||
|
placeholderText: "请选择升级文件或将文件拖入工具中"
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "选择"
|
||||||
|
onClicked: fileDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: 10
|
||||||
|
ProgressBar {
|
||||||
|
id:progressBar
|
||||||
|
Layout.fillWidth: true
|
||||||
|
from: 0
|
||||||
|
to:100
|
||||||
|
value: 0.0
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
id:progressText
|
||||||
|
text: "0%"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Text {
|
||||||
|
id: otaMessage
|
||||||
|
text: "请选择升级文件,点击开始按钮升级模组"
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "开始"
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
onClicked: {
|
||||||
|
otaMessage.color = "black"
|
||||||
|
App.startOta(otaFile.text)
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed: {
|
||||||
|
if (onClose)
|
||||||
|
onClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
FileDialog {
|
||||||
|
id: fileDialog
|
||||||
|
nameFilters: ["OTA文件 (*.Pkg)"]
|
||||||
|
currentFolder: StandardPaths.standardLocations(
|
||||||
|
StandardPaths.DesktopLocation)[0]
|
||||||
|
onAccepted: {
|
||||||
|
var fileUrl = fileDialog.selectedFile.toString()
|
||||||
|
var localFilePath = fileUrl.startsWith(
|
||||||
|
"file:///") ? fileUrl.substring(8) : fileUrl
|
||||||
|
otaFile.text = localFilePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: App
|
||||||
|
function onUpdateFinished() {
|
||||||
|
otaMessage.text = "OTA升级完成"
|
||||||
|
otaMessage.color = "green"
|
||||||
|
}
|
||||||
|
function onOtaMessage(message) {
|
||||||
|
otaMessage.text = message
|
||||||
|
}
|
||||||
|
function onOtaProgressChanged(progress){
|
||||||
|
progressBar.value = progress;
|
||||||
|
progressText.text = `${progress}%`
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ import Analyser
|
|||||||
|
|
||||||
Window {
|
Window {
|
||||||
width: 1120
|
width: 1120
|
||||||
height: 640
|
height: 680
|
||||||
visible: true
|
visible: true
|
||||||
title: qsTr(Qt.application.name + " " + Qt.application.version)
|
title: qsTr(Qt.application.name + " " + Qt.application.version)
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets SerialPort)
|
|||||||
|
|
||||||
set(PROJECT_SOURCES OtaUpdate.rc
|
set(PROJECT_SOURCES OtaUpdate.rc
|
||||||
main.cpp
|
main.cpp
|
||||||
CdcUpdater.h CdcUpdater.cpp
|
|
||||||
Widget.cpp
|
Widget.cpp
|
||||||
Widget.h
|
Widget.h
|
||||||
)
|
)
|
||||||
@ -18,7 +17,6 @@ qt_add_executable(SmartLockerUpdater
|
|||||||
|
|
||||||
target_link_libraries(SmartLockerUpdater
|
target_link_libraries(SmartLockerUpdater
|
||||||
PRIVATE Peripheral
|
PRIVATE Peripheral
|
||||||
PRIVATE Encrypt
|
|
||||||
PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
|
PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
PRIVATE Qt${QT_VERSION_MAJOR}::SerialPort
|
PRIVATE Qt${QT_VERSION_MAJOR}::SerialPort
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
|
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS SerialPort)
|
||||||
|
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS SerialPort)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
add_library(Peripheral
|
add_library(Peripheral
|
||||||
DeviceDiscovery.h DeviceDiscovery.cpp
|
DeviceDiscovery.h DeviceDiscovery.cpp
|
||||||
|
CdcUpdater.h CdcUpdater.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(Peripheral
|
target_include_directories(Peripheral
|
||||||
@ -8,8 +14,10 @@ target_include_directories(Peripheral
|
|||||||
|
|
||||||
target_link_libraries(Peripheral
|
target_link_libraries(Peripheral
|
||||||
PUBLIC Universal
|
PUBLIC Universal
|
||||||
|
PRIVATE Encrypt
|
||||||
PRIVATE Mfreadwrite
|
PRIVATE Mfreadwrite
|
||||||
PRIVATE Mf
|
PRIVATE Mf
|
||||||
PRIVATE mfplat
|
PRIVATE mfplat
|
||||||
PRIVATE mfuuid
|
PRIVATE mfuuid
|
||||||
|
PRIVATE Qt${QT_VERSION_MAJOR}::SerialPort
|
||||||
)
|
)
|
||||||
|
@ -106,7 +106,8 @@ void CdcUpdater::transferBin() {
|
|||||||
auto readSize = m_ifs->gcount();
|
auto readSize = m_ifs->gcount();
|
||||||
|
|
||||||
if (readSize > 0) {
|
if (readSize > 0) {
|
||||||
m_progress += (99 - m_progressBeforeTranster) * static_cast<float>(m_packetIndex) / m_totalPackageSize;
|
m_progress = m_progressBeforeTranster +
|
||||||
|
(99 - m_progressBeforeTranster) * static_cast<float>(m_packetIndex) / m_totalPackageSize;
|
||||||
if (m_progress > 99) m_progress = 99;
|
if (m_progress > 99) m_progress = 99;
|
||||||
emit progressChanged(m_progress);
|
emit progressChanged(m_progress);
|
||||||
|
|
||||||
@ -138,7 +139,7 @@ void CdcUpdater::onReadyRead() {
|
|||||||
if (command == EnterUpgradeReply) {
|
if (command == EnterUpgradeReply) {
|
||||||
write(GetVersion);
|
write(GetVersion);
|
||||||
emit progressChanged(++m_progress);
|
emit progressChanged(++m_progress);
|
||||||
message("获取模组OTA版本......");
|
emit message("获取模组OTA版本......");
|
||||||
} else if (command == GetVersionReply) {
|
} else if (command == GetVersionReply) {
|
||||||
LOG(info) << "device ota version: 0x" << std::hex << (static_cast<int>(data[4]) & 0xff);
|
LOG(info) << "device ota version: 0x" << std::hex << (static_cast<int>(data[4]) & 0xff);
|
||||||
int fileSize = std::filesystem::file_size(m_path);
|
int fileSize = std::filesystem::file_size(m_path);
|
||||||
@ -150,7 +151,7 @@ void CdcUpdater::onReadyRead() {
|
|||||||
content[2] = 0x14;
|
content[2] = 0x14;
|
||||||
write(StartUpgrade, content.data(), content.size());
|
write(StartUpgrade, content.data(), content.size());
|
||||||
emit progressChanged(++m_progress);
|
emit progressChanged(++m_progress);
|
||||||
message("模组进入升级状态......");
|
emit message("模组进入升级状态......");
|
||||||
} else if (command == StartUpgradeReply) {
|
} else if (command == StartUpgradeReply) {
|
||||||
std::ifstream ifs(m_path, std::ifstream::binary);
|
std::ifstream ifs(m_path, std::ifstream::binary);
|
||||||
char buffer[4096] = {0};
|
char buffer[4096] = {0};
|
@ -56,6 +56,7 @@ HOST_TOOLS := /opt/Xuantie-900-gcc-elf-newlib-x86_64-V2.6.1/bin
|
|||||||
上述步骤执行完毕之后,即可编译打包:
|
上述步骤执行完毕之后,即可编译打包:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
./boot-rebuild.sh # 编译boot
|
||||||
./rebuild-app.sh y L015 V200 R002 # 编译烧录固件
|
./rebuild-app.sh y L015 V200 R002 # 编译烧录固件
|
||||||
./rebuild-app-ota.sh y L015 V200 R002 14 # 编译OTA固件,11为OTA版本号
|
./rebuild-app-ota.sh y L015 V200 R002 14 # 编译OTA固件,11为OTA版本号
|
||||||
600X800
|
600X800
|
||||||
|
Loading…
Reference in New Issue
Block a user