SWUpdate 官方说明文档:
https://zqb-all.github.io/swupdate/swupdate.html
//main.cpp
/***********************************
*@file
*@brief
*@author
*@e-mail:
*@company
*@date
************************************/
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
//common_def.h
/***********************************
*@file
*@brief
*@author
*@e-mail:
*@company
*@date
************************************/
#ifndef COMMON_DEF_H
#define COMMON_DEF_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <stdbool.h>
#include "network_ipc.h"
#include <QDebug>
static char buf[256];
static int fd = STDIN_FILENO;
static int verbose = 1;
static bool dry_run = false;
static bool run_postupdate = false;
static int end_status = EXIT_SUCCESS;
static pthread_mutex_t mymutex;
/*
* this is the callback to get a new chunk of the
* image.
* It is called by a thread generated by the library and
* can block.
*/
static int readimage(char **p, int *size) {
int ret;
ret = read(fd, buf, sizeof(buf));
*p = buf;
*size = ret;
return ret;
}
/*
* This is called by the library to inform
* about the current status of the upgrade
*/
static int printstatus(ipc_message *msg)
{
if (verbose)
fprintf(stdout, "Status: %d message: %s\n",
msg->data.status.current,
strlen(msg->data.status.desc) > 0 ? msg->data.status.desc : "");
return 0;
}
/*
* this is called at the end reporting the status
* of the upgrade and running any post-update actions
* if successful
*/
static int end(RECOVERY_STATUS status)
{
end_status = (status == SUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE;
fprintf(stdout, "Swupdate %s\n",
status == FAILURE ? "*failed* !" :
"was successful !");
if (status == SUCCESS && run_postupdate) {
fprintf(stdout, "Executing post-update actions.\n");
ipc_message msg;
if (ipc_postupdate(&msg) != 0)
fprintf(stderr, "Running post-update failed!\n");
}
pthread_mutex_unlock(&mymutex);
return 0;
}
/*
* Send file to main swupdate process
*/
static int send_file(const char* filename) {
int rc;
if (filename && (fd = open(filename, O_RDONLY)) < 0) {
fprintf(stderr, "Unable to open %s\n", filename);
return EXIT_FAILURE;
}
/* synchronize with a mutex */
pthread_mutex_lock(&mymutex);
/* May be set non-zero by end() function on failure */
end_status = EXIT_SUCCESS;
rc = swupdate_async_start(readimage, printstatus,
end, dry_run);
/* return if we've hit an error scenario */
if (rc < 0) {
fprintf(stderr, "swupdate_async_start returns %d\n", rc);
pthread_mutex_unlock(&mymutex);
close(fd);
return EXIT_FAILURE;
}
/* Now block */
pthread_mutex_lock(&mymutex);
/* End called, unlock and exit */
pthread_mutex_unlock(&mymutex);
if (filename)
close(fd);
return end_status;
}
#endif // COMMON_DEF_H
//MainWindow.h
/***********************************
*@file
*@brief
*@author
*@e-mail:
*@company
*@date
************************************/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "StartSwupdateThread.h"
#include "UpdateTextEditThread.h"
#include <QProcess>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void StartSWUpdateSoftWare();
void StartStartSh();
private slots:
void on_btn_select_file_clicked();
void on_btn_upgrade_clicked();
void on_btn_cancel_clicked();
void slot_update_textedit(QString text );
private:
Ui::MainWindow *ui;
StartSwupdateThread m_start_sw_thread;
UpdateTextEditThread m_update_text_thread;
QSharedPointer<QProcess> my_process{nullptr};
};
#endif // MAINWINDOW_H
//network_ipc.h
/*
* (C) Copyright 2008-2017
* Stefano Babic, DENX Software Engineering, sbabic@denx.de.
* on behalf of ifm electronic GmbH
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _IPC_H
#define _IPC_H
#include <stdlib.h>
#include <stdbool.h>
#include "swupdate_status.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Be careful to include further headers here. This file is the interface
* to external programs interfacing with SWUpdate as client, and further
* headers are not exported.
*/
#define IPC_MAGIC 0x14052001
typedef enum {
REQ_INSTALL,
ACK,
NACK,
GET_STATUS,
POST_UPDATE,
SWUPDATE_SUBPROCESS,
REQ_INSTALL_DRYRUN,
SET_AES_KEY
} msgtype;
/*
* Commands are used for IPC to subprocesses. The meaning is then interpreted
* by the single subprocess
*/
enum {
CMD_ACTIVATION, /* this returns the answer if a SW can be activated */
CMD_CONFIG,
CMD_ENABLE /* Enable or disable suricatta mode */
};
typedef union {
char msg[128];
struct {
int current;
int last_result;
int error;
char desc[2048];
} status;
struct {
sourcetype source; /* Who triggered the update */
int cmd; /* Optional encoded command */
int timeout; /* timeout in seconds if an aswer is expected */
unsigned int len; /* Len of data valid in buf */
char buf[2048]; /*
* Buffer that each source can fill
* with additional information
*/
} instmsg;
struct {
char key_ascii[65]; /* Key size in ASCII (256 bit, 32 bytes bin) + termination */
char ivt_ascii[33]; /* Key size in ASCII (16 bytes bin) + termination */
} aeskeymsg;
} msgdata;
typedef struct {
int magic; /* magic number */
int type;
msgdata data;
} ipc_message;
char *get_ctrl_socket(void);
int ipc_inst_start(void);
int ipc_inst_start_ext(sourcetype source, size_t len, const char *info, bool dry_run);
int ipc_send_data(int connfd, char *buf, int size);
void ipc_end(int connfd);
int ipc_get_status(ipc_message *msg);
int ipc_get_status_timeout(ipc_message *msg, unsigned int timeout_ms);
int ipc_postupdate(ipc_message *msg);
int ipc_send_cmd(ipc_message *msg);
typedef int (*writedata)(char **buf, int *size);
typedef int (*getstatus)(ipc_message *msg);
typedef int (*terminated)(RECOVERY_STATUS status);
int ipc_wait_for_complete(getstatus callback);
int swupdate_image_write(char *buf, int size);
int swupdate_async_start(writedata wr_func, getstatus status_func,
terminated end_func, bool dry_run);
#ifdef __cplusplus
} // extern "C"
#endif
#endif
//StartSwupdateThread.h
/***********************************
*@file
*@brief
*@author
*@e-mail:
*@company
*@date
************************************/
#ifndef STARTSWUPDATETHREAD_H
#define STARTSWUPDATETHREAD_H
#include <QObject>
#include <QThread>
#include <QDebug>
class StartSwupdateThread :public QThread
{
Q_OBJECT
public:
StartSwupdateThread();
~StartSwupdateThread() override ;
void run() override;
signals:
void signal_start_status(QString str );
public:
bool m_start_status{false};
};
#endif // STARTSWUPDATETHREAD_H
//swupdate_status.h
/*
* (C) Copyright 2015-2017
* Stefano Babic, DENX Software Engineering, sbabic@denx.de.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _SWUPDATE_STATUS_H
#define _SWUPDATE_STATUS_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* This is used to send back the result of an update.
* It is strictly forbidden to change the order of entries.
* New values should be put at the end without altering the order.
*/
typedef enum {
IDLE,
START,
RUN,
SUCCESS,
FAILURE,
DOWNLOAD,
DONE,
SUBPROCESS,
PROGRESS,
} RECOVERY_STATUS;
typedef enum {
SOURCE_UNKNOWN,
SOURCE_WEBSERVER,
SOURCE_SURICATTA,
SOURCE_DOWNLOADER,
SOURCE_LOCAL
} sourcetype;
#ifdef __cplusplus
} // extern "C"
#endif
#endif
//UpdateTextEditThread.h
/***********************************
*@file
*@brief
*@author
*@e-mail:
*@company
*@date
************************************/
#ifndef UPDATETEXTEDITTHREAD_H
#define UPDATETEXTEDITTHREAD_H
#include <QObject>
#include <QThread>
#include "common_def.h"
class UpdateTextEditThread : public QThread
{
Q_OBJECT
public:
UpdateTextEditThread();
~UpdateTextEditThread();
void run() override;
signals:
void signal_update_text(QString text);
public:
bool m_is_stop{false};
};
#endif // UPDATETEXTEDITTHREAD_H
//MainWindow.cpp
/***********************************
*@file
*@brief
*@author
*@e-mail:
*@company
*@date
************************************/
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QFileDialog>
#include <QProcess>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&m_update_text_thread, &UpdateTextEditThread::signal_update_text, this, &MainWindow::slot_update_textedit);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::StartSWUpdateSoftWare()
{
QString program = "/home/xsf/demo/sbabic/swupdate/swupdate";
QStringList arguments;
arguments << " -w " << "\"--document-root ./examples/www/v2 --port 8080\" " ;
if(!my_process)
my_process = QSharedPointer< QProcess>::create();
my_process->start(program,arguments);
my_process->waitForStarted();
qDebug().noquote() << __FUNCTION__ << arguments<<my_process->arguments() ;
qDebug() << __FUNCTION__ << my_process->processId() << my_process->state()<< my_process->pid() ;
}
void MainWindow::StartStartSh()
{
QString cmd = "/home/xsf/temp/QtProjects/Q5_9_C_Demo/UpgradeDemo/start_sw.sh" ;
// system(cmd.toStdString().c_str());
QString program = "./start_sw.h";
if(!my_process)
{
my_process = QSharedPointer< QProcess>::create(this);
my_process->setEnvironment(my_process->environment());
}
my_process->start("sh " + cmd/*program*/);
my_process->waitForStarted();
qDebug().noquote() << __FUNCTION__ <<my_process->arguments() ;
qDebug() << __FUNCTION__ << my_process->processId() << my_process->state()<< my_process->pid() ;
}
void MainWindow::on_btn_select_file_clicked()
{
QString str = QFileDialog::getOpenFileName(this,tr("select file"),"/home/xsf/demo/sbabic/swupdate/xsf_test");
ui->swu_file_path->setText(str);
}
void MainWindow::on_btn_upgrade_clicked()
{
if(ui->swu_file_path->text().isEmpty())
{
qDebug() << "ui->swu_file_path->text().isEmpty()";
return;
}
///solution 1
// StartSWUpdateSoftWare();
///solution 2
// if(!m_start_sw_thread.isRunning())
// {
// m_start_sw_thread.start();
// }
// m_start_sw_thread.wait();
///solution 3
StartStartSh();
usleep(5000000);
//solution 4
if(!m_update_text_thread.isRunning())
{
m_update_text_thread.start();
}
m_update_text_thread.wait();
qDebug() << __FUNCTION__ << my_process->processId() << my_process->state()<< my_process->pid() ;
// my_process->kill();
// my_process->terminate();
system("killall swupdate");
usleep(1000000);
qDebug() << __FUNCTION__ << my_process->processId() << my_process->state()<< my_process->pid() ;
}
void MainWindow::on_btn_cancel_clicked()
{
close();
}
void MainWindow::slot_update_textedit(QString text)
{
ui->textedit->append(text);
}
StartSwupdateThread.cpp
/***********************************
*@file
*@brief
*@author
*@e-mail:
*@company
*@date
************************************/
#include "StartSwupdateThread.h"
StartSwupdateThread::StartSwupdateThread()
{
}
StartSwupdateThread::~StartSwupdateThread()
{
}
void StartSwupdateThread::run()
{
// QString cmd ;
// cmd = "/home/xsf/demo/sbabic/swupdate/swupdate -w \"--document-root ./examples/www/v2 --port 8080\" " ;
// qDebug() <<__FUNCTION__ ;
// system(cmd.toStdString().c_str());
QString cmd = "/home/xsf/temp/QtProjects/Q5_9_C_Demo/UpgradeDemo/start_sw.sh" ;
system(cmd.toStdString().c_str());
qDebug() <<__FUNCTION__ ;
}
UpdateTextEditThread.cpp
/***********************************
*@file
*@brief
*@author
*@e-mail:
*@company
*@date
************************************/
#include "UpdateTextEditThread.h"
#include <QDebug>
UpdateTextEditThread::UpdateTextEditThread()
{
}
UpdateTextEditThread::~UpdateTextEditThread()
{
}
void UpdateTextEditThread::run()
{
if (!m_is_stop) {
QString str = "Start Upgrade " ;
qDebug() << __FUNCTION__ << str ;
emit signal_update_text(str);
pthread_mutex_init(&mymutex, NULL);
QString swu_file = "/home/xsf/demo/sbabic/swupdate/xsf_test/my-software_1.0.swu";
int ret = send_file(swu_file.toStdString().c_str());
qDebug() << __FUNCTION__ <<" send_file ret value :"<< ret ;
str = ret ==0 ? "Upgrade success !" : "Upgrade fail!" ;
emit signal_update_text(str);
usleep(1000000);
m_is_stop = true ;
}
}
start_sw.sh
cd /home/xsf/demo/sbabic/swupdate
echo "this is start_sw.sh file"
killall swupdate
/home/xsf/demo/sbabic/swupdate/swupdate -w "--document-root ./examples/www/v2 --port 8080"
create .swu file
///MakeFile
CONTAINER_VER="1.0"
PRODUCT_NAME="my-software"
FILES="sw-description 1.txt 2.txt 3.txt "
for i in $FILES;do
echo $i;done | cpio -ov -H crc > ${PRODUCT_NAME}_${CONTAINER_VER}.swu
///sw-description
software =
{
version = "0.1.0";
description = "Firmware update for XXXXX Project";
hardware-compatibility: [ "1.0", "1.2", "1.3"];
files: (
{
filename = "1.txt";
path = "/home/xsf/test/1.txt";
},
{
filename = "2.txt";
path = "/home/xsf/test/2.txt";
} ,
{
filename = "3.txt";
path = "/home/xsf/test/3.txt";
}
);
}