mirror of
https://github.com/eliboa/TegraRcmGUI.git
synced 2025-01-31 22:05:01 +00:00
libs & dark theme
This commit is contained in:
parent
014f7766c9
commit
bef72f5cd0
34 changed files with 3058 additions and 223 deletions
|
@ -1,9 +1,10 @@
|
|||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
RC_ICONS = res/TegraRcmGUI.ico
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any Qt feature that has been marked deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
|
@ -16,16 +17,40 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
|||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
kourou/kourou.cpp \
|
||||
kourou/libs/rcm_device.cpp \
|
||||
main.cpp \
|
||||
qkourou.cpp \
|
||||
qpayload.cpp \
|
||||
qtools.cpp \
|
||||
qutils.cpp \
|
||||
tegrarcmgui.cpp
|
||||
|
||||
HEADERS += \
|
||||
tegrarcmgui.h
|
||||
kourou/kourou.h \
|
||||
kourou/libs/libusbk_int.h \
|
||||
kourou/libs/rcm_device.h \
|
||||
kourou/usb_command.h \
|
||||
qkourou.h \
|
||||
qpayload.h \
|
||||
qtools.h \
|
||||
qutils.h \
|
||||
rcm_device.h \
|
||||
tegrarcmgui.h \
|
||||
types.h
|
||||
|
||||
FORMS += \
|
||||
qpayload.ui \
|
||||
qtools.ui \
|
||||
tegrarcmgui.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
TRANSLATIONS = languages/tegrarcmgui_fr.ts
|
||||
|
||||
LIBS += -L$$PWD/../../../../../../../libusbK-dev-kit/bin/lib/amd64/ -llibusbK
|
||||
INCLUDEPATH += $$PWD/../../../../../../../libusbK-dev-kit/includes
|
||||
DEPENDPATH += $$PWD/../../../../../../../libusbK-dev-kit/includes
|
||||
|
||||
RESOURCES += \
|
||||
qresources.qrc
|
||||
|
||||
DISTFILES +=
|
||||
|
|
|
@ -1,6 +1,201 @@
|
|||
/*
|
||||
* Copyright (c) 2020 eliboa
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "kourou.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
Kourou::Kourou()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Kourou::initDevice(KLST_DEVINFO_HANDLE deviceInfo)
|
||||
{
|
||||
m_rcm_ready = RcmDevice::initDevice(deviceInfo);
|
||||
m_ariane_ready = false;
|
||||
|
||||
// If RCM device is not ready, check if Ariane is already loaded
|
||||
if (!m_rcm_ready && getStatus() == CONNECTED)
|
||||
{
|
||||
m_ariane_ready = arianeIsReady_sync();
|
||||
return m_ariane_ready;
|
||||
}
|
||||
return m_rcm_ready;
|
||||
}
|
||||
|
||||
void Kourou::disconnect()
|
||||
{
|
||||
RcmDevice::disconnect();
|
||||
m_rcm_ready = false;
|
||||
m_ariane_ready = false;
|
||||
}
|
||||
|
||||
int Kourou::sdmmc_writeFile(const char* in_path, const char* out_path, bool create_always)
|
||||
{
|
||||
char* fileMemBlock = nullptr;
|
||||
ifstream file(in_path, ios::in | ios::binary | ios::ate);
|
||||
UC_SDIO uc;
|
||||
auto end = [&] (int rc) {
|
||||
if(file.is_open()) file.close();
|
||||
if (fileMemBlock != nullptr) delete[] fileMemBlock;
|
||||
return rc;
|
||||
};
|
||||
|
||||
if (strlen(out_path) > array_countof(uc.path)-1)
|
||||
return PATH_TOO_LONG;
|
||||
|
||||
if (!file.is_open())
|
||||
return OPEN_FILE_FAILED;
|
||||
|
||||
// Check file size
|
||||
if (file.tellg() > MAX_FILE_SIZE) // 100MB max
|
||||
return end(FILE_TOO_LARGE);
|
||||
|
||||
// Create command
|
||||
memset(uc.path, 0, array_countof(uc.path));
|
||||
uc.command = WRITE_SD_FILE;
|
||||
strcpy_s(uc.path, array_countof(uc.path), out_path);
|
||||
uc.file_size = file.tellg();
|
||||
file.seekg(0, ios::beg);
|
||||
|
||||
// Send command to device
|
||||
int bytesSent = write((const u8*)&uc, sizeof(uc));
|
||||
if (bytesSent != sizeof(uc))
|
||||
return end(SEND_COMMAND_FAILED);
|
||||
|
||||
// Allocate memory for file
|
||||
fileMemBlock = new char[uc.file_size];
|
||||
file.read(fileMemBlock, uc.file_size);
|
||||
|
||||
return end(sendBinPackets(fileMemBlock, uc.file_size));
|
||||
}
|
||||
|
||||
int Kourou::sendBinPackets(char* buffer, u32 len)
|
||||
{
|
||||
u32 curOffset = 0, bytesRemaining = len;
|
||||
u8 buf[USB_BUFFER_LENGTH];
|
||||
u32 dataBufSize = USB_BUFFER_LENGTH - 32;
|
||||
while(bytesRemaining > 0)
|
||||
{
|
||||
memset(buf, 0, USB_BUFFER_LENGTH);
|
||||
UC_BlockHeader bh;
|
||||
bh.block_size = bytesRemaining > dataBufSize ? dataBufSize : bytesRemaining;
|
||||
bh.block_full_size = 0; // no compression
|
||||
memcpy_s(&buf[0], sizeof(UC_BlockHeader), &bh, sizeof(UC_BlockHeader));
|
||||
memcpy_s(&buf[32], bh.block_size, &buffer[curOffset], bh.block_size);
|
||||
u32 fbs = bh.block_size + 32;
|
||||
|
||||
if (write((const u8*)&buf[0], fbs) != int(fbs))
|
||||
return USB_WRITE_FAILED;
|
||||
|
||||
// Get confirmation
|
||||
u32 bytesReceived = 0;
|
||||
if (!readResponse(&bytesReceived, sizeof(u32)))
|
||||
return USB_WRITE_FAILED;
|
||||
if (bytesReceived != bh.block_size)
|
||||
return USB_WRITE_FAILED;
|
||||
|
||||
bytesRemaining -= bh.block_size;
|
||||
}
|
||||
return int(len);
|
||||
}
|
||||
|
||||
bool Kourou::readResponse(void* buffer, u32 size)
|
||||
{
|
||||
u32 res_size = RESPONSE_MAX_SIZE - sizeof(u16);
|
||||
u8 tmp_buffer[RESPONSE_MAX_SIZE - sizeof(u16)];
|
||||
if (size > res_size)
|
||||
return false;
|
||||
else res_size = size + sizeof(u16);
|
||||
|
||||
if (read(tmp_buffer, res_size) != int(res_size))
|
||||
return false;
|
||||
|
||||
u16* signature = (u16*)tmp_buffer;
|
||||
if (*signature != RESPONSE)
|
||||
return false;
|
||||
|
||||
memcpy(buffer, &tmp_buffer[sizeof(u16)], size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Kourou::arianeIsReady_sync()
|
||||
{
|
||||
auto end = [&](bool ready) {
|
||||
m_ariane_ready = ready;
|
||||
return ready;
|
||||
};
|
||||
|
||||
if (RcmDevice::deviceIsReady())
|
||||
{
|
||||
m_rcm_ready = true;
|
||||
return end(false);
|
||||
}
|
||||
else m_rcm_ready = false;
|
||||
|
||||
u8 buff[0x10];
|
||||
static const char READY_INDICATOR[] = "READY.\n";
|
||||
int bytesRead = 0;
|
||||
|
||||
flushPipe(READ_PIPE_ID);
|
||||
|
||||
UC_Header uc;
|
||||
uc.command = GET_STATUS;
|
||||
if (write((const u8*)&uc, sizeof(uc)) != sizeof(uc))
|
||||
return end(false);
|
||||
|
||||
if ((bytesRead = read(&buff[0], 0x10)) > 0 && memcmp(&buff[0], READY_INDICATOR, array_countof(READY_INDICATOR) - 1) == 0)
|
||||
return end(true);
|
||||
|
||||
return end(false);
|
||||
}
|
||||
|
||||
int Kourou::getDeviceInfo(UC_DeviceInfo* di)
|
||||
{
|
||||
UC_Header uc;
|
||||
uc.command = GET_DEVICE_INFO;
|
||||
if(write((const u8*)&uc, sizeof(uc)) != sizeof(uc))
|
||||
return SEND_COMMAND_FAILED;
|
||||
|
||||
if(read((u8*)di, sizeof(UC_DeviceInfo)) != sizeof(UC_DeviceInfo))
|
||||
return RECEIVE_COMMAND_FAILED;
|
||||
|
||||
if (di->signature != DEVINFO)
|
||||
return RECEIVE_COMMAND_FAILED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Kourou::rebootToRcm()
|
||||
{
|
||||
if (!arianeIsReady_sync())
|
||||
return false;
|
||||
|
||||
UC_Header uc;
|
||||
uc.command = REBOOT_RCM;
|
||||
// Send command
|
||||
write((const u8*)&uc, sizeof(uc));
|
||||
|
||||
// Get response
|
||||
bool response = false;
|
||||
if (!readResponse(&response, sizeof(bool)))
|
||||
return false;
|
||||
|
||||
return response;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2020 eliboa
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Kourou is a C++ child class derived from base class "RcmDevice"
|
||||
* This class provides additionnal functions for communicating with Ariane (backend payload based program)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KOUROU_H
|
||||
#define KOUROU_H
|
||||
#include "libs/rcm_device.h"
|
||||
#include "usb_command.h"
|
||||
|
||||
typedef enum _KRESULT : DWORD
|
||||
{
|
||||
RCM_REBOOT_FAILED = 0x00F,
|
||||
ARIANE_NOT_READY = 0x010,
|
||||
WRONG_PARAM_GENERIC = 0x011
|
||||
|
||||
class Kourou
|
||||
} KRESULT;
|
||||
|
||||
class Kourou : public RcmDevice
|
||||
{
|
||||
public:
|
||||
Kourou();
|
||||
bool initDevice(KLST_DEVINFO_HANDLE deviceInfo = nullptr);
|
||||
void disconnect();
|
||||
|
||||
int sdmmc_writeFile(const char* in_path, const char* out_path, bool create_always = false);
|
||||
int getDeviceInfo(UC_DeviceInfo* di);
|
||||
bool arianeIsReady() { return m_ariane_ready; }
|
||||
bool rcmIsReady() { return m_rcm_ready; }
|
||||
void setRcmReady(bool b) { m_rcm_ready = b; }
|
||||
bool arianeIsReady_sync();
|
||||
void setArianeReady(bool b) { m_ariane_ready = b; }
|
||||
bool rebootToRcm();
|
||||
|
||||
private:
|
||||
int sendBinPackets(char* buffer, u32 len);
|
||||
bool readResponse(void* buffer, u32 size);
|
||||
bool m_ariane_ready = false;
|
||||
bool m_rcm_ready = false;
|
||||
};
|
||||
|
||||
#endif // KOUROU_H
|
||||
|
|
|
@ -1,3 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2020 eliboa
|
||||
* Copyright (c) 2018 ktemkin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "rcm_device.h"
|
||||
#include <winioctl.h>
|
||||
#include <iostream>
|
||||
|
@ -8,80 +25,107 @@ using namespace std;
|
|||
RcmDevice::RcmDevice()
|
||||
{
|
||||
m_currentBuffer = 0;
|
||||
m_b_RcmReady = false;
|
||||
m_usbAPI_loaded = false;
|
||||
m_devIsInitialized = false;
|
||||
m_devStatus = DISCONNECTED;
|
||||
}
|
||||
|
||||
bool RcmDevice::initDevice(KLST_DEVINFO_HANDLE deviceInfo)
|
||||
{
|
||||
m_b_RcmReady = false;
|
||||
|
||||
if (deviceInfo != nullptr)
|
||||
m_devInfo = deviceInfo;
|
||||
else
|
||||
getPluggedDevice();
|
||||
|
||||
if (m_devInfo != nullptr && loadDevice() == SUCCESS)
|
||||
m_b_RcmReady = true;
|
||||
|
||||
return m_b_RcmReady;
|
||||
}
|
||||
|
||||
bool RcmDevice::getPluggedDevice()
|
||||
RcmDevice::~RcmDevice()
|
||||
{
|
||||
if (m_devList != nullptr)
|
||||
LstK_Free(m_devList);
|
||||
|
||||
u32 devCount = 0;
|
||||
|
||||
if (!LstK_Init(&m_devList, KLST_FLAG_NONE))
|
||||
return false;
|
||||
|
||||
LstK_Count(m_devList, &devCount);
|
||||
|
||||
if (devCount == 0 || !LstK_FindByVidPid(m_devList, RCM_VID, RCM_PID, &m_devInfo))
|
||||
return false;
|
||||
|
||||
if (m_devInfo == nullptr)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
if (m_usbAPI_loaded)
|
||||
m_usbApi.Free(m_usbHandle);
|
||||
}
|
||||
|
||||
RRESULT RcmDevice::loadDevice()
|
||||
{
|
||||
if (m_devInfo == nullptr)
|
||||
return DEVICE_NOT_FOUND;
|
||||
bool RcmDevice::initDevice(KLST_DEVINFO_HANDLE deviceInfo)
|
||||
{
|
||||
auto error = [&](DWORD err_code){
|
||||
SetLastError(err_code);
|
||||
return false;
|
||||
};
|
||||
|
||||
if (deviceInfo != nullptr && (deviceInfo->Common.Vid != RCM_VID && deviceInfo->Common.Pid != RCM_PID))
|
||||
return error(WRONG_DEVICE_VID_PID);
|
||||
|
||||
KLST_DEVINFO_HANDLE tmp_devInfo = deviceInfo != nullptr ? deviceInfo : m_devInfo;
|
||||
if(tmp_devInfo == nullptr && !getPluggedDevice(&tmp_devInfo))
|
||||
return error(DEVICE_NOT_FOUND);
|
||||
|
||||
// New device already initialized & connected, return ready state (no need to load anything else)
|
||||
if (m_devInfo != nullptr && m_devStatus == CONNECTED && m_devInfo->DeviceID == tmp_devInfo->DeviceID)
|
||||
return deviceIsReady() ? true : error(DEVICE_NOT_READY);
|
||||
|
||||
// Init device
|
||||
m_devInfo = tmp_devInfo;
|
||||
m_devIsInitialized = false;
|
||||
|
||||
if (m_devInfo->DriverID != KUSB_DRVID_LIBUSBK)
|
||||
return MISSING_LIBUSBK_DRIVER;
|
||||
return error(MISSING_LIBUSBK_DRIVER);
|
||||
|
||||
LibK_LoadDriverAPI(&m_usbApi, m_devInfo->DriverID);
|
||||
// Load driver API
|
||||
if (!m_usbAPI_loaded)
|
||||
{
|
||||
LibK_LoadDriverAPI(&m_usbApi, KUSB_DRVID_LIBUSBK);
|
||||
m_usbAPI_loaded = true;
|
||||
}
|
||||
|
||||
// Init USB handle
|
||||
m_usbApi.Free(m_usbHandle); // Free previous usb handle
|
||||
if (!m_usbApi.Init(&m_usbHandle, m_devInfo))
|
||||
return DEVICE_HANDLE_FAILED;
|
||||
return error(DEVICE_HANDLE_FAILED);
|
||||
|
||||
// Verify libusbk version
|
||||
libusbk::libusb_request req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
int res = Ioctl(libusbk::LIBUSB_IOCTL_GET_VERSION, &req, sizeof(req), &req, sizeof(req));
|
||||
|
||||
if (res <= 0)
|
||||
return DEVICE_HANDLE_FAILED;
|
||||
return error(DEVICE_HANDLE_FAILED);
|
||||
|
||||
libusbk::version_t usbkVersion = req.version;
|
||||
if (usbkVersion.major != 3 || usbkVersion.minor != 0 || usbkVersion.micro != 7)
|
||||
return LIBUSBK_WRONG_DRIVER;
|
||||
return error(LIBUSBK_WRONG_DRIVER);
|
||||
|
||||
vector<u8> deviceId(0x10, 0);
|
||||
if(read(&deviceId[0], 0x10) != int(deviceId.size()))
|
||||
return DEVICEID_READ_FAILED;
|
||||
m_devIsInitialized = true;
|
||||
m_devStatus = CONNECTED;
|
||||
|
||||
return SUCCESS;
|
||||
// Set pipes timeout policy
|
||||
u32 pipe_timeout = 2000; //ms
|
||||
m_usbApi.SetPipePolicy(m_usbHandle, READ_PIPE_ID, PIPE_TRANSFER_TIMEOUT, sizeof(u32), &pipe_timeout);
|
||||
m_usbApi.SetPipePolicy(m_usbHandle, WRITE_PIPE_ID, PIPE_TRANSFER_TIMEOUT, sizeof(u32), &pipe_timeout);
|
||||
|
||||
// Device is initialized, return ready state
|
||||
return deviceIsReady() ? true : error(DEVICE_NOT_READY);
|
||||
}
|
||||
|
||||
// This function returns true if device is ready to receive RCM commands.
|
||||
// It doesn't mean the device is eXploitable !
|
||||
bool RcmDevice::deviceIsReady()
|
||||
{
|
||||
if (!m_devIsInitialized || m_devStatus != CONNECTED)
|
||||
return false;
|
||||
|
||||
// Generate a GET_STATUS request
|
||||
u16 trash = 0; // GET_STATUS returns 2 bytes
|
||||
libusbk::libusb_request req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.timeout= 500;
|
||||
req.status.index = 0;
|
||||
req.status.recipient = 0x02;
|
||||
|
||||
int res = Ioctl(libusbk::LIBUSB_IOCTL_GET_STATUS, &req, sizeof(req), &trash, sizeof(u16));
|
||||
|
||||
if (res < 0) // If device's stack is already smashed, res = -141 (timeout)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
int RcmDevice::read(u8* buffer, size_t bufferSize)
|
||||
{
|
||||
size_t bytesRead;
|
||||
if (!m_usbApi.ReadPipe(m_usbHandle, 0x81, buffer, bufferSize, &bytesRead, nullptr))
|
||||
u32 bytesRead;
|
||||
if (!m_usbApi.ReadPipe(m_usbHandle, READ_PIPE_ID, buffer, bufferSize, &bytesRead, nullptr))
|
||||
return -int(GetLastError());
|
||||
|
||||
return int(bytesRead);
|
||||
|
@ -94,10 +138,10 @@ int RcmDevice::write(const u8* buffer, size_t bufferSize)
|
|||
|
||||
while (bytesRemaining > 0)
|
||||
{
|
||||
const size_t bytesToWrite = (bytesRemaining < PACKET_SIZE) ? bytesRemaining : PACKET_SIZE;
|
||||
const u32 bytesToWrite = (bytesRemaining < PACKET_SIZE) ? bytesRemaining : PACKET_SIZE;
|
||||
m_currentBuffer = (m_currentBuffer == 0) ? 1u : 0u;
|
||||
size_t bytesTransfered = 0;
|
||||
if(!m_usbApi.WritePipe(m_usbHandle, 0x01, (u8*)&buffer[bytesWritten], bytesToWrite, &bytesTransfered, nullptr))
|
||||
u32 bytesTransfered = 0;
|
||||
if(!m_usbApi.WritePipe(m_usbHandle, WRITE_PIPE_ID, (u8*)&buffer[bytesWritten], bytesToWrite, &bytesTransfered, nullptr))
|
||||
return -int(GetLastError());
|
||||
|
||||
bytesWritten += bytesTransfered;
|
||||
|
@ -107,6 +151,19 @@ int RcmDevice::write(const u8* buffer, size_t bufferSize)
|
|||
return int(bytesWritten);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Fusée Gelée eXploit
|
||||
* -------------------
|
||||
* Vulnerability : CVE-2018-6242
|
||||
* Author / Reporter : Katherine Temkin (@ktemkin)
|
||||
* Affiliation : ReSwitched
|
||||
* Disclosure : public disclosure planned for June 15th, 2018 ^^
|
||||
* Credits : @Qyriad for fusée launcher
|
||||
* @rajkosto for the Windows reimplementation (TegraRcmSmash)
|
||||
*
|
||||
*/
|
||||
|
||||
const byte BUILTIN_INTERMEZZO[] =
|
||||
{
|
||||
0x44, 0x00, 0x9F, 0xE5, 0x01, 0x11, 0xA0, 0xE3, 0x40, 0x20, 0x9F, 0xE5, 0x00, 0x20, 0x42, 0xE0,
|
||||
|
@ -117,29 +174,18 @@ const byte BUILTIN_INTERMEZZO[] =
|
|||
0x5C, 0xF0, 0x01, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x01, 0x40
|
||||
};
|
||||
|
||||
/*
|
||||
* Fusée Gelée eXploit
|
||||
* -------------------
|
||||
* Author / Reporter : Katherine Temkin (@ktemkin)
|
||||
* Affiliation : ReSwitched
|
||||
* Disclosure : public disclosure planned for June 15th, 2018 ^^
|
||||
* Credits : @rajkosto for windows reimplementation (TegraRcmSmash)
|
||||
*
|
||||
*/
|
||||
RRESULT RcmDevice::hack(const char* user_payload_path)
|
||||
{
|
||||
// Control user payload
|
||||
ifstream userPayload(user_payload_path, ios::in | ios::binary | ios::ate);
|
||||
|
||||
if (!userPayload.is_open())
|
||||
return OPEN_FILE_FAILED;
|
||||
|
||||
const auto userPayloadSize = int(userPayload.tellg());
|
||||
if (userPayloadSize > 0x1ED58)
|
||||
if (userPayloadSize > PAYLOAD_MAX_SIZE)
|
||||
return PAYLOAD_TOO_LARGE;
|
||||
|
||||
// Read the user payload file into memory & release file
|
||||
userPayload.seekg(0, ios::beg);
|
||||
|
||||
char *userPayloadBuffer = new char[userPayloadSize];
|
||||
userPayload.read(&userPayloadBuffer[0], userPayloadSize);
|
||||
bool error = !(userPayload) || int(userPayload.tellg()) != userPayloadSize;
|
||||
|
@ -149,6 +195,32 @@ RRESULT RcmDevice::hack(const char* user_payload_path)
|
|||
delete[] userPayloadBuffer;
|
||||
return OPEN_FILE_FAILED;
|
||||
}
|
||||
|
||||
RRESULT res = hack((u8*)userPayloadBuffer, (u32)userPayloadSize);
|
||||
|
||||
delete[] userPayloadBuffer;
|
||||
return res;
|
||||
}
|
||||
|
||||
RRESULT RcmDevice::hack(u8 *payload_buff, u32 buff_size)
|
||||
{
|
||||
if (!m_devIsInitialized)
|
||||
return DEVICE_NOT_SET;
|
||||
else if (m_devStatus != CONNECTED)
|
||||
return DEVICE_DISCONNECTED;
|
||||
else if (!deviceIsReady())
|
||||
return DEVICE_NOT_READY;
|
||||
|
||||
if (buff_size > PAYLOAD_MAX_SIZE)
|
||||
return PAYLOAD_TOO_LARGE;
|
||||
|
||||
m_currentBuffer = 0;
|
||||
|
||||
// Read device id first.
|
||||
vector<u8> deviceId(0x10, 0);
|
||||
if (read(&deviceId[0], 0x10) != int(deviceId.size()))
|
||||
return DEVICE_NOT_READY;
|
||||
|
||||
// Inits
|
||||
std::vector<byte> payload; // Full payload (relocator + user payload)
|
||||
size_t currOffset = 0; // Payload current offset
|
||||
|
@ -189,10 +261,9 @@ RRESULT RcmDevice::hack(const char* user_payload_path)
|
|||
currOffset += paddingSize;
|
||||
|
||||
// Include the user payload in the command stream
|
||||
payload.resize(payload.size() + userPayloadSize);
|
||||
memcpy(&payload[currOffset], &userPayloadBuffer[0], userPayloadSize);
|
||||
currOffset += userPayloadSize;
|
||||
delete[] userPayloadBuffer;
|
||||
payload.resize(payload.size() + buff_size);
|
||||
memcpy(&payload[currOffset], &payload_buff[0], buff_size);
|
||||
currOffset += buff_size;
|
||||
|
||||
// Pad the payload to fill a USB request exactly, so we don't send a short
|
||||
// packet and break out of the RCM loop
|
||||
|
@ -211,27 +282,58 @@ RRESULT RcmDevice::hack(const char* user_payload_path)
|
|||
|
||||
// The RCM backend alternates between two different DMA buffers. Ensure we're about to DMA
|
||||
// into the higher one, so we have less to copy during our attack.
|
||||
if (switchToHighBuffer() != 0)
|
||||
// Warning! If device reboot to RCM, resetCurrentBuffer() must be called otherwise we'll swith to lower buffer instead
|
||||
u32 sres = switchToHighBuffer();
|
||||
if (sres != 0 && (sres < 0 || sres != PACKET_SIZE))
|
||||
return SW_HIGHBUFF_FAILED;
|
||||
|
||||
// Smash the stack
|
||||
// Finally, to trigger the memcpy vulnerability itself, we need to send a
|
||||
// long length "GET_STATUS" request to the endpoint
|
||||
int stLength = RCM_PAYLOAD_ADDR - getCurrentBufferAddress();
|
||||
std::vector<byte> threshBuf(stLength, 0);
|
||||
|
||||
std::vector<byte> threshBuf(stLength, 0);
|
||||
libusbk::libusb_request req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.timeout= 1000;
|
||||
req.status.index = 0;
|
||||
req.status.recipient = 0x02;
|
||||
|
||||
// Request device
|
||||
int res = Ioctl(libusbk::LIBUSB_IOCTL_GET_STATUS, &req, sizeof(req), &threshBuf[0], threshBuf.size());
|
||||
|
||||
// If stack is smashed, the request will timeout
|
||||
// If the device is an ipatched unit or Mariko+, the request will likely return 0 (or < 0)
|
||||
if (res <= 0 && -res != ERROR_SEM_TIMEOUT)
|
||||
return STACK_SMASH_FAILED;
|
||||
else
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
///// PRIVATE METHODS /////
|
||||
////////////////////////////////////////////
|
||||
|
||||
// Find a plugged USB device matching Tegra RCM pID and vID.
|
||||
bool RcmDevice::getPluggedDevice(KLST_DEVINFO_HANDLE *devinfo)
|
||||
{
|
||||
if (m_devList != nullptr)
|
||||
LstK_Free(m_devList);
|
||||
|
||||
u32 devCount = 0;
|
||||
|
||||
if (!LstK_Init(&m_devList, KLST_FLAG_NONE))
|
||||
return false;
|
||||
|
||||
LstK_Count(m_devList, &devCount);
|
||||
|
||||
if (devCount == 0 || !LstK_FindByVidPid(m_devList, RCM_VID, RCM_PID, devinfo))
|
||||
return false;
|
||||
|
||||
if (devinfo == nullptr)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Send an IOCTL request to USB endpoint
|
||||
int RcmDevice::Ioctl(DWORD ioctlCode, const void* inputBytes, size_t numInputBytes, void* outputBytes, size_t numOutputBytes)
|
||||
{
|
||||
HANDLE driverHandle = INVALID_HANDLE_VALUE;
|
||||
|
@ -255,9 +357,9 @@ int RcmDevice::Ioctl(DWORD ioctlCode, const void* inputBytes, size_t numInputByt
|
|||
if (!GetOverlappedResult(driverHandle, &overlapped, &bytesReceived, true))
|
||||
return -int(GetLastError());
|
||||
|
||||
return bytesReceived;
|
||||
return int(bytesReceived);
|
||||
}
|
||||
|
||||
// Switch to higher DMA buffer
|
||||
int RcmDevice::switchToHighBuffer()
|
||||
{
|
||||
if (m_currentBuffer == 0)
|
||||
|
@ -271,9 +373,6 @@ int RcmDevice::switchToHighBuffer()
|
|||
|
||||
return writeRes;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,17 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2020 eliboa
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RCMDEVICE_H
|
||||
#define RCMDEVICE_H
|
||||
|
||||
#include <windows.h>
|
||||
#include "libusbk_int.h"
|
||||
#include "../types.h"
|
||||
#include <string>
|
||||
#include "../../types.h"
|
||||
|
||||
#define PACKET_SIZE 0x1000
|
||||
#define PAYLOAD_MAX_SIZE 0x1ED58
|
||||
|
||||
static int RCM_VID = 0x0955;
|
||||
static int RCM_PID = 0x7321;
|
||||
static UCHAR READ_PIPE_ID = 0x81;
|
||||
static UCHAR WRITE_PIPE_ID = 0x01;
|
||||
|
||||
typedef enum _RESULT
|
||||
typedef enum _RESULT : DWORD
|
||||
{
|
||||
SUCCESS = 0x000,
|
||||
LIBUSBK_WRONG_DRIVER = 0x001,
|
||||
|
@ -23,19 +42,28 @@ typedef enum _RESULT
|
|||
USB_WRITE_FAILED = 0x007,
|
||||
SW_HIGHBUFF_FAILED = 0x008,
|
||||
STACK_SMASH_FAILED = 0x009,
|
||||
DEVICEID_READ_FAILED = 0x00A
|
||||
DEVICEID_READ_FAILED = 0x00A,
|
||||
DEVICE_NOT_READY = 0x00B,
|
||||
DEVICE_NOT_SET = 0x00C,
|
||||
WRONG_DEVICE_VID_PID = 0x00D,
|
||||
DEVICE_DISCONNECTED = 0x00E
|
||||
|
||||
} RRESULT;
|
||||
|
||||
typedef enum _DEVICE_STATUS {
|
||||
DISCONNECTED,
|
||||
CONNECTED
|
||||
} DEVICE_STATUS;
|
||||
|
||||
class RcmDevice
|
||||
{
|
||||
|
||||
////////////////////////////////////////////
|
||||
///// PUBLIC METHODS /////
|
||||
////////////////////////////////////////////
|
||||
public:
|
||||
//! Rcm device constructor
|
||||
//! Rcm device constructor
|
||||
RcmDevice();
|
||||
~RcmDevice();
|
||||
////////////////////////////////////////////
|
||||
///// PUBLIC METHODS /////
|
||||
////////////////////////////////////////////
|
||||
|
||||
/*!
|
||||
* \brief Initialize a RCM device. This function must be called at least on time before any other method call
|
||||
|
@ -44,7 +72,7 @@ public:
|
|||
*
|
||||
* \returns
|
||||
* - on success, true.
|
||||
* - on failure, false.
|
||||
* - on failure, false (use GetLastError() to get error code)
|
||||
*/
|
||||
bool initDevice(KLST_DEVINFO_HANDLE deviceInfo = nullptr);
|
||||
|
||||
|
@ -57,6 +85,17 @@ public:
|
|||
* - on failure, see enum RRESULT
|
||||
*/
|
||||
RRESULT hack(const char* payload_path);
|
||||
/*!
|
||||
* \brief Constructs a RCM payload and smash the device stack (fusée gelée exploit)
|
||||
* \param payload_buff
|
||||
* Pointer to the payload data
|
||||
* \param buff_size
|
||||
* Payload size
|
||||
* \returns
|
||||
* - on success, SUCCESS (0)
|
||||
* - on failure, see enum RRESULT
|
||||
*/
|
||||
RRESULT hack(u8 *payload_buff, u32 buff_size);
|
||||
|
||||
/*!
|
||||
* \brief Read a buffer from USB pipe
|
||||
|
@ -79,12 +118,24 @@ public:
|
|||
int write(const u8* buffer, size_t bufferSize);
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the device is ready or not
|
||||
* \brief Check whether the device is ready to receive RCM commands
|
||||
* \return true if device is ready
|
||||
*/
|
||||
bool isDeviceReady() { return m_b_RcmReady; };
|
||||
bool deviceIsReady();
|
||||
|
||||
//! Get the RCM device status (CONNECTED / DISCONNECTED)
|
||||
DEVICE_STATUS getStatus() { return m_devStatus; }
|
||||
//! Set the RCM device status to DISCONNECTED
|
||||
void disconnect() { m_devStatus = DISCONNECTED; }
|
||||
|
||||
// API Getters
|
||||
bool flushPipe(UCHAR pipeId) { return m_usbApi.FlushPipe(m_usbHandle, pipeId); }
|
||||
|
||||
// Reset the current buffer to lower one. Use this with caution.
|
||||
// Current buffer should not be reset manually, except after a controlled RCM reboot er disconnection.
|
||||
// disconnect() method should be preferred
|
||||
void resetCurrentBuffer() { m_currentBuffer = 0; }
|
||||
|
||||
// member variables
|
||||
private:
|
||||
bool m_is_devicePlugged;
|
||||
KLST_DEVINFO_HANDLE m_devInfo = nullptr;
|
||||
|
@ -92,12 +143,12 @@ private:
|
|||
KUSB_DRIVER_API m_usbApi;
|
||||
KLST_HANDLE m_devList = nullptr;
|
||||
u32 m_currentBuffer = 0;
|
||||
bool m_b_RcmReady;
|
||||
bool m_devIsInitialized = false;
|
||||
bool m_usbAPI_loaded = false;
|
||||
DEVICE_STATUS m_devStatus;
|
||||
|
||||
// private methods
|
||||
private:
|
||||
RRESULT loadDevice();
|
||||
bool getPluggedDevice();
|
||||
bool getPluggedDevice(KLST_DEVINFO_HANDLE *devinfo);
|
||||
int switchToHighBuffer();
|
||||
u32 getCurrentBufferAddress() const { return m_currentBuffer == 0 ? 0x40005000u : 0x40009000u; }
|
||||
int Ioctl(DWORD ioctlCode, const void* inputBytes, size_t numInputBytes, void* outputBytes, size_t numOutputBytes);
|
||||
|
@ -115,7 +166,6 @@ public:
|
|||
_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
void swap(WinHandle&& other) noexcept { std::swap(_handle, other._handle); }
|
||||
|
||||
WinHandle(WinHandle&& moved) noexcept : _handle(INVALID_HANDLE_VALUE) { swap(std::move(moved)); }
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <iostream>
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
|
@ -43,29 +40,26 @@ using std::string;
|
|||
#include <cstdlib>
|
||||
using std::exit;
|
||||
|
||||
#define CRYPTOPP_INCLUDE_CRYPTLIB <CRYPTOLIB_HEADER_PREFIX/cryptlib.h>
|
||||
#define CRYPTOPP_INCLUDE_CMAC <CRYPTOLIB_HEADER_PREFIX/cmac.h>
|
||||
#define CRYPTOPP_INCLUDE_AES <CRYPTOLIB_HEADER_PREFIX/aes.h>
|
||||
#define CRYPTOPP_INCLUDE_HEX <CRYPTOLIB_HEADER_PREFIX/hex.h>
|
||||
#define CRYPTOPP_INCLUDE_FILTERS <CRYPTOLIB_HEADER_PREFIX/filters.h>
|
||||
#define CRYPTOPP_INCLUDE_SECBLOCK <CRYPTOLIB_HEADER_PREFIX/secblock.h>
|
||||
|
||||
#include CRYPTOPP_INCLUDE_CRYPTLIB
|
||||
#include CRYPTOPP_INCLUDE_CMAC
|
||||
#include CRYPTOPP_INCLUDE_AES
|
||||
#include CRYPTOPP_INCLUDE_HEX
|
||||
#include CRYPTOPP_INCLUDE_FILTERS
|
||||
#include CRYPTOPP_INCLUDE_SECBLOCK
|
||||
|
||||
#include "cryptlib.h"
|
||||
using CryptoPP::Exception;
|
||||
|
||||
#include "cmac.h"
|
||||
using CryptoPP::CMAC;
|
||||
|
||||
#include "aes.h"
|
||||
using CryptoPP::AES;
|
||||
|
||||
#include "hex.h"
|
||||
using CryptoPP::HexEncoder;
|
||||
using CryptoPP::HexDecoder;
|
||||
|
||||
#include "filters.h"
|
||||
using CryptoPP::StringSink;
|
||||
using CryptoPP::StringSource;
|
||||
using CryptoPP::HashFilter;
|
||||
using CryptoPP::HashVerificationFilter;
|
||||
|
||||
#include "secblock.h"
|
||||
using CryptoPP::SecByteBlock;
|
||||
|
||||
extern "C" int cmac_hash(const unsigned char *msg, int len, unsigned char *cmac_buf)
|
||||
|
|
|
@ -137,7 +137,7 @@ typedef struct {
|
|||
} nv3p_cmd_status_t;
|
||||
|
||||
/*
|
||||
* nv3p_platform_info_t: retrieves the system information. All parameters
|
||||
* nv3p_platform_info_t: retrieves the system information. All paramters
|
||||
* are output parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
|
|
|
@ -113,6 +113,10 @@ typedef struct {
|
|||
#define RCM_OP_MODE_ODM_OPEN 0x5
|
||||
#define RCM_OP_MODE_ODM_SECURE_PKC 0x6
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int rcm_init(uint32_t version, const char *keyfile);
|
||||
uint32_t rcm_get_msg_len(uint8_t *msg);
|
||||
int rcm_create_msg(
|
||||
|
@ -123,4 +127,8 @@ int rcm_create_msg(
|
|||
uint32_t payload_len,
|
||||
uint8_t **msg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _RCM_H
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <iostream>
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
|
@ -43,39 +40,36 @@ using std::string;
|
|||
#include <cstdlib>
|
||||
using std::exit;
|
||||
|
||||
#define CRYPTOPP_INCLUDE_CRYPTLIB <CRYPTOLIB_HEADER_PREFIX/cryptlib.h>
|
||||
#define CRYPTOPP_INCLUDE_FILES <CRYPTOLIB_HEADER_PREFIX/files.h>
|
||||
#define CRYPTOPP_INCLUDE_FILTERS <CRYPTOLIB_HEADER_PREFIX/filters.h>
|
||||
#define CRYPTOPP_INCLUDE_INTEGER <CRYPTOLIB_HEADER_PREFIX/integer.h>
|
||||
#define CRYPTOPP_INCLUDE_OSRNG <CRYPTOLIB_HEADER_PREFIX/osrng.h>
|
||||
#define CRYPTOPP_INCLUDE_QUEUE <CRYPTOLIB_HEADER_PREFIX/queue.h>
|
||||
#define CRYPTOPP_INCLUDE_RSA <CRYPTOLIB_HEADER_PREFIX/rsa.h>
|
||||
#define CRYPTOPP_INCLUDE_PSSR <CRYPTOLIB_HEADER_PREFIX/pssr.h>
|
||||
#define CRYPTOPP_INCLUDE_SHA <CRYPTOLIB_HEADER_PREFIX/sha.h>
|
||||
#define CRYPTOPP_INCLUDE_SECBLOCK <CRYPTOLIB_HEADER_PREFIX/secblock.h>
|
||||
|
||||
#include CRYPTOPP_INCLUDE_CRYPTLIB
|
||||
#include CRYPTOPP_INCLUDE_FILES
|
||||
#include CRYPTOPP_INCLUDE_FILTERS
|
||||
#include CRYPTOPP_INCLUDE_INTEGER
|
||||
#include CRYPTOPP_INCLUDE_OSRNG
|
||||
#include CRYPTOPP_INCLUDE_QUEUE
|
||||
#include CRYPTOPP_INCLUDE_RSA
|
||||
#include CRYPTOPP_INCLUDE_PSSR
|
||||
#include CRYPTOPP_INCLUDE_SHA
|
||||
#include CRYPTOPP_INCLUDE_SECBLOCK
|
||||
|
||||
#include "cryptlib.h"
|
||||
using CryptoPP::Exception;
|
||||
|
||||
#include "integer.h"
|
||||
using CryptoPP::Integer;
|
||||
|
||||
#include "files.h"
|
||||
using CryptoPP::FileSource;
|
||||
|
||||
#include "filters.h"
|
||||
using CryptoPP::StringSink;
|
||||
using CryptoPP::SignerFilter;
|
||||
|
||||
#include "queue.h"
|
||||
using CryptoPP::ByteQueue;
|
||||
|
||||
#include "rsa.h"
|
||||
using CryptoPP::RSA;
|
||||
using CryptoPP::RSASS;
|
||||
|
||||
#include "pssr.h"
|
||||
using CryptoPP::PSS;
|
||||
|
||||
#include "sha.h"
|
||||
using CryptoPP::SHA256;
|
||||
|
||||
#include "secblock.h"
|
||||
using CryptoPP::SecByteBlock;
|
||||
|
||||
#include "osrng.h"
|
||||
using CryptoPP::AutoSeededRandomPool;
|
||||
|
||||
#include "rsa-pss.h"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011-2016, NVIDIA CORPORATION
|
||||
< * Copyright (c) 2011-2016, NVIDIA CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -76,6 +76,7 @@ static int usb_match(libusb_device *dev, uint16_t venid, uint16_t *devid
|
|||
}
|
||||
switch (desc.idProduct & 0xff) {
|
||||
case USB_DEVID_NVIDIA_TEGRA20:
|
||||
case USB_DEVID_NINTENDO_SWITCH:
|
||||
case USB_DEVID_NVIDIA_TEGRA30:
|
||||
case USB_DEVID_NVIDIA_TEGRA114:
|
||||
case USB_DEVID_NVIDIA_TEGRA124:
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#include <stdbool.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
#if defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01000102)
|
||||
#define HAVE_USB_PORT_MATCH
|
||||
#define PORT_MATCH_MAX_PORTS 7
|
||||
|
@ -39,10 +42,14 @@
|
|||
|
||||
#define USB_VENID_NVIDIA 0x955
|
||||
#define USB_DEVID_NVIDIA_TEGRA20 0x20
|
||||
#define USB_DEVID_NINTENDO_SWITCH 0x21
|
||||
#define USB_DEVID_NVIDIA_TEGRA30 0x30
|
||||
#define USB_DEVID_NVIDIA_TEGRA114 0x35
|
||||
#define USB_DEVID_NVIDIA_TEGRA124 0x40
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
typedef struct {
|
||||
libusb_device_handle *handle;
|
||||
uint8_t iface_num;
|
||||
|
|
|
@ -1,13 +1,24 @@
|
|||
#pragma once
|
||||
#include "windows.h"
|
||||
#ifndef UCOMMAND_H
|
||||
#define UCOMMAND_H
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long int u64;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
#define COMMAND 0x5543
|
||||
#define BIN_PACKET 0x4249
|
||||
#define EXEC_COMMAND 0x4558
|
||||
#define COMMAND 0x5543
|
||||
#define BIN_PACKET 0x4249
|
||||
#define EXEC_COMMAND 0x4558
|
||||
#define RESPONSE 0x5245
|
||||
#define DEVINFO 0x4445
|
||||
|
||||
#define MAX_FILE_SIZE 0x6400000 //100MB
|
||||
#define SUCCESS 0
|
||||
#define USB_BUFFER_LENGTH 0x1000
|
||||
#define RESPONSE_MAX_SIZE 0x20
|
||||
|
||||
#define FS_FAT32 3
|
||||
#define FS_EXFAT 4
|
||||
|
||||
typedef enum _UC_CommandType : u8
|
||||
{
|
||||
|
@ -16,7 +27,9 @@ typedef enum _UC_CommandType : u8
|
|||
READ_SD_FILE,
|
||||
WRITE_SD_FILE,
|
||||
PUSH_PAYLOAD,
|
||||
REBOOT_RCM
|
||||
REBOOT_RCM,
|
||||
GET_DEVICE_INFO,
|
||||
GET_STATUS
|
||||
|
||||
} UC_CommandType;
|
||||
|
||||
|
@ -50,7 +63,38 @@ typedef struct _UC_EXEC
|
|||
typedef struct _UC_BlockHeader
|
||||
{
|
||||
u16 signature = BIN_PACKET;
|
||||
int block_size;
|
||||
int block_full_size; // Full size if LZ4 compressed
|
||||
u32 block_size;
|
||||
u32 block_full_size; // Full size if LZ4 compressed
|
||||
|
||||
} UC_BlockHeader;
|
||||
|
||||
typedef struct _UC_DeviceInfo
|
||||
{
|
||||
u16 signature = DEVINFO; // UC signature
|
||||
u32 battery_capacity; // Fuel gauge
|
||||
bool autoRCM; // autoRCM state
|
||||
u32 burnt_fuses; // Number of burnt fuses
|
||||
bool sdmmc_initialized; // MMC FS initialized
|
||||
u8 emmc_fs_type; // 3 is FAT32, 4 is exFAT
|
||||
u16 emmc_fs_cl_size; // Cluster size in sectors (always 512B per sectors)
|
||||
DWORD emmc_fs_last_cl; // Last allocated cluster
|
||||
DWORD emmc_fs_free_cl; // Number of free cluster
|
||||
bool cfw_sxos; // SX OS bootloader
|
||||
bool cfw_ams; // AMS fusee
|
||||
bool cbl_hekate; // Hekate
|
||||
|
||||
} UC_DeviceInfo;
|
||||
|
||||
/*--------------*/
|
||||
/* ERROR CODES */
|
||||
/*--------------*/
|
||||
// FS
|
||||
#define OPEN_FILE_FAILED -0x0001
|
||||
#define FILE_TOO_LARGE -0x0002
|
||||
#define PATH_TOO_LONG -0x0003
|
||||
// COM
|
||||
#define SEND_COMMAND_FAILED -0x1001
|
||||
#define RECEIVE_COMMAND_FAILED -0x1002
|
||||
#define USB_WRITE_FAILED -0x1003
|
||||
|
||||
#endif // UCOMMAND_H
|
||||
|
|
9
main.cpp
9
main.cpp
|
@ -1,11 +1,20 @@
|
|||
#include "tegrarcmgui.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTranslator>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QApplication a(argc, argv);
|
||||
a.setStyleSheet("QMainWindow{ border-radius: 20px; }");
|
||||
QTranslator appTranslator;
|
||||
//appTranslator.load(QLocale(), QLatin1String("tegrarcmgui"), QLatin1String("_"), QLatin1String(":/i18n"));
|
||||
appTranslator.load("tegrarcmgui_fr", "languages");
|
||||
a.installTranslator(&appTranslator);
|
||||
TegraRcmGUI w;
|
||||
w.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
|
|
202
qkourou.cpp
202
qkourou.cpp
|
@ -1,6 +1,206 @@
|
|||
#include "qkourou.h"
|
||||
#include <winioctl.h>
|
||||
#include <QDateTime>
|
||||
#include <QThread>
|
||||
#include <QDebug>
|
||||
|
||||
QKourou::QKourou()
|
||||
QKourou::QKourou(QWidget *parent, Kourou* device, TegraRcmGUI* gui) : QWidget(parent), m_device(device), parent(parent), m_gui(gui)
|
||||
{
|
||||
qRegisterMetaType<UC_DeviceInfo>("UC_DeviceInfo");
|
||||
connect(this, SIGNAL(clb_deviceInfo(UC_DeviceInfo)), parent, SLOT(on_deviceInfo_received(UC_DeviceInfo)));
|
||||
connect(this, SIGNAL(clb_error(int)), parent, SLOT(error(int)));
|
||||
connect(this, SIGNAL(clb_deviceStateChange()), parent, SLOT(on_deviceStateChange()));
|
||||
connect(this, SIGNAL(clb_finished(int)), parent, SLOT(on_Kourou_finished(int)));
|
||||
}
|
||||
|
||||
void QKourou::initDevice(bool silent, KLST_DEVINFO_HANDLE deviceInfo)
|
||||
{
|
||||
if (!waitUntilUnlock())
|
||||
return;
|
||||
|
||||
DWORD error = 0;
|
||||
bool devInfoSync = false;
|
||||
UC_DeviceInfo di;
|
||||
|
||||
setLockEnabled(true);
|
||||
|
||||
if (!m_device->initDevice(deviceInfo))
|
||||
error = GetLastError();
|
||||
|
||||
emit clb_deviceStateChange();
|
||||
|
||||
bool b_autoInject = false;
|
||||
if (!error)
|
||||
{
|
||||
// Do auto inject if needed
|
||||
DWORD autoErr = autoInject();
|
||||
b_autoInject = !autoErr ? true : false;
|
||||
error = autoErr != WRONG_PARAM_GENERIC ? autoErr : error;
|
||||
|
||||
// Auto boot Ariane
|
||||
if (!error && !b_autoInject && !m_device->arianeIsReady() && autoLaunchAriane && ariane_bin.size())
|
||||
{
|
||||
arianeIsLoading = true;
|
||||
error = m_device->hack((u8*)ariane_bin.data(), (u32)ariane_bin.size());
|
||||
if (!error)
|
||||
m_device->arianeIsReady_sync();
|
||||
|
||||
arianeIsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
setLockEnabled(false);
|
||||
|
||||
if (error && !silent)
|
||||
emit clb_error(int(error));
|
||||
|
||||
if (!error && b_autoInject)
|
||||
emit clb_finished(AUTO_INJECT);
|
||||
|
||||
// Get device info if ariane is ready
|
||||
if (m_device->arianeIsReady())
|
||||
devInfoSync = !(m_device->getDeviceInfo(&di));
|
||||
|
||||
setLockEnabled(false);
|
||||
emit clb_deviceStateChange();
|
||||
|
||||
if (devInfoSync)
|
||||
emit clb_deviceInfo(di);
|
||||
}
|
||||
|
||||
DWORD QKourou::autoInject()
|
||||
{
|
||||
if (!autoInjectPayload)
|
||||
return WRONG_PARAM_GENERIC;
|
||||
|
||||
QString path = m_gui->userSettings->value("autoInjectPath").toString();
|
||||
if (!path.length())
|
||||
return WRONG_PARAM_GENERIC;
|
||||
|
||||
if (!m_device->rcmIsReady() && !m_device->arianeIsReady())
|
||||
return DEVICE_NOT_READY;
|
||||
|
||||
tmp_string.clear();
|
||||
tmp_string.append(path.toStdString());
|
||||
DWORD err = 0;
|
||||
|
||||
// Reboot if ariane is loaded
|
||||
if (m_device->arianeIsReady() && !rebootToRcm())
|
||||
err = GetLastError();
|
||||
|
||||
// Push payload
|
||||
if (!err) err = m_device->hack(tmp_string.c_str());
|
||||
|
||||
if (!err && !m_device->deviceIsReady())
|
||||
m_device->setRcmReady(false);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void QKourou::getDeviceInfo()
|
||||
{
|
||||
qDebug() << "QKourou::getDeviceInfo() execute in " << QThread::currentThreadId();
|
||||
|
||||
if (!waitUntilUnlock())
|
||||
return;
|
||||
|
||||
UC_DeviceInfo di;
|
||||
|
||||
setLockEnabled(true);
|
||||
int res = m_device->getDeviceInfo(&di);
|
||||
setLockEnabled(false);
|
||||
|
||||
if (res)
|
||||
emit clb_error(res);
|
||||
else
|
||||
emit clb_deviceInfo(di);
|
||||
|
||||
}
|
||||
|
||||
void QKourou::hack(const char* payload_path, u8 *payload_buff, u32 buff_size)
|
||||
{
|
||||
if (!waitUntilUnlock())
|
||||
return;
|
||||
|
||||
DWORD res = 0;
|
||||
setLockEnabled(true);
|
||||
|
||||
// Reboot if ariane is loaded
|
||||
if (m_device->arianeIsReady() && !rebootToRcm())
|
||||
res = GetLastError();
|
||||
|
||||
// Push payload
|
||||
if(!res) res = payload_path != nullptr ? m_device->hack(payload_path) : m_device->hack(payload_buff, buff_size);
|
||||
|
||||
if (!res && !m_device->deviceIsReady())
|
||||
m_device->setRcmReady(false);
|
||||
|
||||
setLockEnabled(false);
|
||||
|
||||
if (res)
|
||||
emit clb_error(int(res));
|
||||
else
|
||||
emit clb_finished(PAYLOAD_INJECT);
|
||||
|
||||
emit clb_deviceStateChange();
|
||||
}
|
||||
|
||||
void QKourou::hack(const char* payload_path)
|
||||
{
|
||||
hack(payload_path, nullptr, 0);
|
||||
}
|
||||
void QKourou::hack(u8 *payload_buff, u32 buff_size)
|
||||
{
|
||||
hack(nullptr, payload_buff, buff_size);
|
||||
}
|
||||
|
||||
bool QKourou::rebootToRcm()
|
||||
{
|
||||
DWORD err = !m_device->rebootToRcm() ? RCM_REBOOT_FAILED : 0;
|
||||
|
||||
if (!err)
|
||||
{
|
||||
m_device->disconnect();
|
||||
if(!waitUntilInit(3))
|
||||
err = RCM_REBOOT_FAILED;
|
||||
}
|
||||
|
||||
if (err)
|
||||
SetLastError(err);
|
||||
|
||||
return !err ? true : false;
|
||||
}
|
||||
|
||||
bool QKourou::waitUntilUnlock(uint timeout_s)
|
||||
{
|
||||
qint64 begin_timestamp = QDateTime::currentSecsSinceEpoch();
|
||||
while(isLocked())
|
||||
{
|
||||
if (QDateTime::currentSecsSinceEpoch() > begin_timestamp + timeout_s)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QKourou::waitUntilRcmReady(uint timeout_s)
|
||||
{
|
||||
qint64 begin_timestamp = QDateTime::currentSecsSinceEpoch();
|
||||
while(!m_device->deviceIsReady())
|
||||
{
|
||||
if (QDateTime::currentSecsSinceEpoch() > begin_timestamp + timeout_s)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool QKourou::waitUntilInit(uint timeout_s)
|
||||
{
|
||||
qint64 begin_timestamp = QDateTime::currentSecsSinceEpoch();
|
||||
while(!m_device->initDevice())
|
||||
{
|
||||
if (QDateTime::currentSecsSinceEpoch() > begin_timestamp + timeout_s)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
58
qkourou.h
58
qkourou.h
|
@ -3,11 +3,65 @@
|
|||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QThread>
|
||||
#include "kourou/kourou.h"
|
||||
#include "tegrarcmgui.h"
|
||||
|
||||
class QKourou
|
||||
typedef enum _qKourouAction : int
|
||||
{
|
||||
INIT_DEVICE,
|
||||
AUTO_INJECT,
|
||||
PAYLOAD_INJECT
|
||||
|
||||
} qKourouAction;
|
||||
|
||||
|
||||
class TegraRcmGUI;
|
||||
|
||||
///
|
||||
/// \brief The QKourou class is a Qt thread safe reimplemented class of Kourou class, for TegraRcmGUI
|
||||
///
|
||||
|
||||
class QKourou : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QKourou();
|
||||
QKourou(QWidget *parent, Kourou* device, TegraRcmGUI* gui);
|
||||
bool isLocked() { return m_locked; }
|
||||
QByteArray ariane_bin;
|
||||
bool autoLaunchAriane = true;
|
||||
bool autoInjectPayload = false;
|
||||
bool arianeIsLoading = false;
|
||||
|
||||
private:
|
||||
Kourou *m_device;
|
||||
TegraRcmGUI *m_gui;
|
||||
bool m_locked = false;
|
||||
bool m_force_lock = false;
|
||||
QWidget *parent;
|
||||
std::string tmp_string;
|
||||
void hack(const char* payload_path, u8 *payload_buff, u32 buff_size);
|
||||
void setLockEnabled(bool enable) { m_locked = enable; }
|
||||
bool waitUntilUnlock(uint timeout_s = 10);
|
||||
bool waitUntilRcmReady(uint timeout_s = 10);
|
||||
bool waitUntilInit(uint timeout_s = 10);
|
||||
bool rebootToRcm();
|
||||
DWORD autoInject();
|
||||
|
||||
|
||||
public slots:
|
||||
void initDevice(bool silent, KLST_DEVINFO_HANDLE deviceInfo = nullptr);
|
||||
void getDeviceInfo();
|
||||
void hack(const char* payload_path);
|
||||
void hack(u8 *payload_buff, u32 buff_size);
|
||||
|
||||
|
||||
signals:
|
||||
void clb_deviceInfo(UC_DeviceInfo di);
|
||||
void clb_error(int error);
|
||||
void clb_deviceStateChange();
|
||||
void clb_finished(int res);
|
||||
|
||||
};
|
||||
|
||||
#endif // QKOUROU_H
|
||||
|
|
382
qpayload.cpp
382
qpayload.cpp
|
@ -1,6 +1,386 @@
|
|||
#include <QDebug>
|
||||
#include "qpayload.h"
|
||||
#include "ui_qpayload.h"
|
||||
#include "qutils.h"
|
||||
|
||||
QPayloadWidget::QPayloadWidget(QWidget *parent) : QWidget(parent)
|
||||
/////////////////////////////////////////////////////////////
|
||||
/// \brief QPayloadWidget::QPayloadWidget
|
||||
/// \param parent
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
QPayloadWidget::QPayloadWidget(TegraRcmGUI *parent) : QWidget(parent)
|
||||
, ui(new Ui::QPayloadWidget), parent(parent)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_kourou = parent->m_kourou;
|
||||
m_device = &parent->m_device;
|
||||
connect(this, SIGNAL(error(int)), parent, SLOT(error(int)));
|
||||
|
||||
// Payload model
|
||||
m_payloadModel = new PayloadModel(this);
|
||||
/// Populate model
|
||||
readFavoritesFromFile();
|
||||
/// Connect model to table view
|
||||
ui->payload_tableView->setModel(m_payloadModel);
|
||||
|
||||
// Payload view
|
||||
const auto view = ui->payload_tableView;
|
||||
view->verticalHeader()->hide();
|
||||
view->horizontalHeader()->hide();
|
||||
view->hideColumn(1);
|
||||
view->setColumnWidth(0, view->width());
|
||||
view->setAlternatingRowColors(true);
|
||||
view->show();
|
||||
|
||||
auto item = ui->payload_tableView->findChildren<QAbstractItemView*>();
|
||||
for (int i = 0; i < item.count(); i++)
|
||||
{
|
||||
item.at(i)->setStatusTip("test");
|
||||
}
|
||||
|
||||
|
||||
// Timers
|
||||
QTimer *payloadBtnStatus_timer = new QTimer(this);
|
||||
connect(payloadBtnStatus_timer, SIGNAL(timeout()), this, SLOT(payloadBtnStatusTimer()));
|
||||
payloadBtnStatus_timer->start(1000); // Every second
|
||||
|
||||
|
||||
|
||||
/// Stylesheets
|
||||
// Apply stylesheet to all buttons
|
||||
QString btnSs = GetStyleSheetFromResFile(":/res/QPushButton.qss");
|
||||
auto buttons = this->findChildren<QPushButton*>();
|
||||
for (int i = 0; i < buttons.count(); i++)
|
||||
{
|
||||
buttons.at(i)->setStyleSheet(btnSs);
|
||||
buttons.at(i)->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
}
|
||||
ui->payload_tableView->setStyleSheet(GetStyleSheetFromResFile(":/res/QTableView.qss"));
|
||||
ui->payloadFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_box02.qss"));
|
||||
|
||||
// Buttons
|
||||
Switch *_switch = new Switch(parent->m_kourou->autoInjectPayload ? true : false, 70);
|
||||
ui->horizontalLayout->addWidget(_switch);
|
||||
connect(_switch, SIGNAL(clicked()), this, SLOT(on_autoInject_toggled()));
|
||||
//ui->injectPayloadBtn->setCursor(Qt::PointingHandCursor);
|
||||
//ui->browsePayloadBtn->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
// ToolTip
|
||||
ui->addFavoriteBtn->setStatusTip(tr("Add current payload selection to favorites"));
|
||||
ui->deleteFavoriteBtn->setStatusTip(tr("Remove selected item from favorites (payload file will not be deleted)"));
|
||||
|
||||
QString ppath = parent->userSettings->value("autoInjectPath").toString();
|
||||
ui->payload_path->setText(ppath);
|
||||
|
||||
}
|
||||
void QPayloadWidget::payloadBtnStatusTimer()
|
||||
{
|
||||
qint64 time = QDateTime::currentSecsSinceEpoch();
|
||||
if (payloadBtnStatusLbl_time && (time + 5 > payloadBtnStatusLbl_time))
|
||||
{
|
||||
ui->payloadBtnStatusLbl->setText("");
|
||||
payloadBtnStatusLbl_time = 0;
|
||||
}
|
||||
}
|
||||
void QPayloadWidget::on_browsePayloadBtn_clicked()
|
||||
{
|
||||
QString path = FileDialog(this, open_file).toLocal8Bit();
|
||||
if (path.length())
|
||||
ui->payload_path->setText(path);
|
||||
}
|
||||
|
||||
void QPayloadWidget::on_injectPayloadBtn_clicked()
|
||||
{
|
||||
if (!m_device->rcmIsReady() && !m_device->arianeIsReady())
|
||||
return;
|
||||
|
||||
if (payloadBtnLock)
|
||||
{
|
||||
ui->payloadBtnStatusLbl->setText(tr("Work in progress"));
|
||||
payloadBtnStatusLbl_time = QDateTime::currentSecsSinceEpoch();
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(ui->payload_path->text().toLocal8Bit().constData());
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
return parent->error(0x005);
|
||||
if (file.size() > PAYLOAD_MAX_SIZE)
|
||||
{
|
||||
file.close();
|
||||
return parent->error(PAYLOAD_TOO_LARGE);
|
||||
}
|
||||
file.close();
|
||||
|
||||
tmp_string.clear();
|
||||
tmp_string.append(ui->payload_path->text().toStdString());
|
||||
payloadBtnLock = true;
|
||||
QtConcurrent::run(m_kourou, &QKourou::hack, tmp_string.c_str());
|
||||
}
|
||||
|
||||
void QPayloadWidget::on_deviceStateChange()
|
||||
{
|
||||
if ((m_device->rcmIsReady() && !m_kourou->autoLaunchAriane) || m_device->arianeIsReady())
|
||||
{
|
||||
payloadBtnLock = false;
|
||||
ui->injectPayloadBtn->setCursor(Qt::PointingHandCursor);
|
||||
ui->injectPayloadBtn->setStatusTip("Inject current payload to device");
|
||||
if (m_payloadModel->rowCount())
|
||||
ui->payload_tableView->setStatusTip(tr("Double-click to inject payload"));
|
||||
}
|
||||
else
|
||||
{
|
||||
payloadBtnLock = true;
|
||||
QString tip = m_device->getStatus() == CONNECTED ? tr("RCM device is not ready. Reboot to RCM") : tr("RCM device undetected!");
|
||||
if (m_kourou->arianeIsLoading)
|
||||
tip = tr("Wait for Ariane to be fully loaded");
|
||||
//ui->injectPayloadBtn->setToolTip(tip);
|
||||
ui->injectPayloadBtn->setStatusTip(tip);
|
||||
ui->injectPayloadBtn->setCursor(Qt::ForbiddenCursor);
|
||||
if (m_payloadModel->rowCount())
|
||||
ui->payload_tableView->setStatusTip(tr("Double-click to push favorite into current selection"));
|
||||
}
|
||||
}
|
||||
|
||||
bool QPayloadWidget::addFavorite(QString name, QString path)
|
||||
{
|
||||
QFile file(path);
|
||||
|
||||
if (!file.exists())
|
||||
return false;
|
||||
|
||||
if (!m_payloadModel->getPayloads().contains({ name, path }))
|
||||
{
|
||||
m_payloadModel->insertRows(0, 1, QModelIndex());
|
||||
QModelIndex index = m_payloadModel->index(0, 0, QModelIndex());
|
||||
m_payloadModel->setData(index, name, Qt::EditRole);
|
||||
index = m_payloadModel->index(0, 1, QModelIndex());
|
||||
m_payloadModel->setData(index, path, Qt::EditRole);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void QPayloadWidget::on_addFavoriteBtn_clicked()
|
||||
{
|
||||
QString path = ui->payload_path->text();
|
||||
if (!path.size())
|
||||
{
|
||||
QMessageBox::information(this, tr("Argument missing"), tr("Payload path is missing"));
|
||||
return;
|
||||
}
|
||||
QFile file(path);
|
||||
if (!file.exists())
|
||||
{
|
||||
QMessageBox::information(this, tr("File missing"), tr("Payload path does not point to a file"));
|
||||
return;
|
||||
}
|
||||
|
||||
QFileInfo info(path);
|
||||
QString name = info.fileName();
|
||||
|
||||
if (m_payloadModel->getPayloads().contains({ path, name }))
|
||||
{
|
||||
QMessageBox::information(this, tr("Duplicate Path"), tr("Payload already in favorites").arg(name));
|
||||
return;
|
||||
}
|
||||
|
||||
if(addFavorite(name, path))
|
||||
writeFavoritesToFile();
|
||||
}
|
||||
|
||||
void QPayloadWidget::on_deleteFavoriteBtn_clicked()
|
||||
{
|
||||
int row = ui->payload_tableView->currentIndex().row();
|
||||
if (row >= 0 && !m_payloadModel->removeRows(row, 1, QModelIndex()))
|
||||
emit error(-1);
|
||||
|
||||
writeFavoritesToFile();
|
||||
}
|
||||
|
||||
void QPayloadWidget::on_autoInject_toggled()
|
||||
{
|
||||
m_kourou->autoInjectPayload = !m_kourou->autoInjectPayload;
|
||||
parent->userSettings->setValue("autoInject", m_kourou->autoInjectPayload);
|
||||
|
||||
if (m_kourou->autoInjectPayload && (m_device->arianeIsReady() || m_device->rcmIsReady()))
|
||||
QtConcurrent::run(m_kourou, &QKourou::initDevice, false, nullptr);
|
||||
}
|
||||
|
||||
void QPayloadWidget::on_payload_path_textChanged(const QString &arg1)
|
||||
{
|
||||
if (!ui->payload_path->text().length())
|
||||
return;
|
||||
|
||||
QString curPath = parent->userSettings->value("autoInjectPath").toString();
|
||||
|
||||
if (curPath == ui->payload_path->text())
|
||||
return;
|
||||
|
||||
parent->userSettings->setValue("autoInjectPath", ui->payload_path->text());
|
||||
|
||||
if (m_kourou->autoInjectPayload && (m_device->arianeIsReady() || m_device->rcmIsReady()))
|
||||
QtConcurrent::run(m_kourou, &QKourou::initDevice, false, nullptr);
|
||||
}
|
||||
|
||||
|
||||
bool QPayloadWidget::readFavoritesFromFile()
|
||||
{
|
||||
QFile pFile(QStringLiteral("payloads.json"));
|
||||
|
||||
if (!pFile.open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
|
||||
QByteArray pData = pFile.readAll();
|
||||
|
||||
pFile.close();
|
||||
|
||||
QJsonDocument loadDoc(QJsonDocument::fromJson(pData));
|
||||
|
||||
QJsonObject json = loadDoc.object();
|
||||
|
||||
QJsonArray pArray = json["favorites"].toArray();
|
||||
int i(0);
|
||||
for (i = 0; i < pArray.size(); i++)
|
||||
{
|
||||
QJsonObject payloadEntry = pArray[i].toObject();
|
||||
QString payload_name = payloadEntry["name"].toString();
|
||||
QString payload_path = payloadEntry["path"].toString();
|
||||
addFavorite(payload_name, payload_path);
|
||||
}
|
||||
|
||||
return i ? true : false;
|
||||
|
||||
}
|
||||
bool QPayloadWidget::writeFavoritesToFile()
|
||||
{
|
||||
|
||||
QFile pFile(QStringLiteral("payloads.json"));
|
||||
|
||||
if (!pFile.open(QIODevice::WriteOnly))
|
||||
return false;
|
||||
|
||||
QJsonArray pArray;
|
||||
QVector<payload_t> payloads = m_payloadModel->getPayloads();
|
||||
for (payload_t paylaod : payloads)
|
||||
{
|
||||
QJsonObject payloadEntry;
|
||||
payloadEntry["name"] = paylaod.name;
|
||||
payloadEntry["path"] = paylaod.path;
|
||||
pArray.append(payloadEntry);
|
||||
}
|
||||
QJsonObject json;
|
||||
json["favorites"] = pArray;
|
||||
QJsonDocument saveDoc(json);
|
||||
pFile.write(saveDoc.toJson());
|
||||
|
||||
pFile.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
/// \brief PayloadModel::PayloadModel
|
||||
/// \param parent
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
PayloadModel::PayloadModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int PayloadModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : int(payloads.size());
|
||||
}
|
||||
|
||||
int PayloadModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : 2;
|
||||
}
|
||||
|
||||
QVariant PayloadModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (index.row() >= payloads.size() || index.row() < 0)
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
const auto &payload = payloads.at(index.row());
|
||||
return !index.column() ? payload.name : payload.path;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool PayloadModel::insertRows(int position, int rows, const QModelIndex &index)
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
beginInsertRows(QModelIndex(), position, position + rows - 1);
|
||||
|
||||
for (int row = 0; row < rows; ++row)
|
||||
payloads.insert(position, { QString(), QString() });
|
||||
|
||||
endInsertRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PayloadModel::removeRows(int position, int rows, const QModelIndex &index)
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
beginRemoveRows(QModelIndex(), position, position + rows - 1);
|
||||
|
||||
for (int row = 0; row < rows; ++row)
|
||||
payloads.removeAt(position);
|
||||
|
||||
endRemoveRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PayloadModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (index.isValid() && role == Qt::EditRole)
|
||||
{
|
||||
const int row = index.row();
|
||||
auto payload = payloads.value(row);
|
||||
|
||||
if (!index.column())
|
||||
payload.name = value.toString();
|
||||
else
|
||||
payload.path = value.toString();
|
||||
|
||||
payloads.replace(row, payload);
|
||||
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::ItemFlags PayloadModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::ItemIsEnabled;
|
||||
|
||||
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
|
||||
}
|
||||
|
||||
const QVector<payload_t> &PayloadModel::getPayloads() const
|
||||
{
|
||||
return payloads;
|
||||
}
|
||||
|
||||
|
||||
void QPayloadWidget::on_payload_tableView_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
QString path = m_payloadModel->getPayloads().at(index.row()).path;
|
||||
ui->payload_path->setText(path);
|
||||
on_injectPayloadBtn_clicked();
|
||||
}
|
||||
|
|
87
qpayload.h
87
qpayload.h
|
@ -1,18 +1,101 @@
|
|||
#ifndef QPAYLOADWIDGET_H
|
||||
#define QPAYLOADWIDGET_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QTableWidget>
|
||||
#include <QAbstractTableModel>
|
||||
#include <QFileSystemModel>
|
||||
#include "tegrarcmgui.h"
|
||||
|
||||
struct payload_t
|
||||
{
|
||||
QString path;
|
||||
QString name;
|
||||
|
||||
bool operator==(const payload_t &other) const
|
||||
{
|
||||
return path == other.path;
|
||||
}
|
||||
};
|
||||
|
||||
inline QDataStream &operator<<(QDataStream &stream, const payload_t &payload)
|
||||
{
|
||||
return stream << payload.name << payload.path;
|
||||
}
|
||||
|
||||
inline QDataStream &operator>>(QDataStream &stream, payload_t &payload)
|
||||
{
|
||||
return stream >> payload.name >> payload.path;
|
||||
}
|
||||
|
||||
|
||||
class TegraRcmGUI;
|
||||
class Kourou;
|
||||
class QKourou;
|
||||
|
||||
class PayloadModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PayloadModel(QObject *parent = nullptr);
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
bool insertRows(int position, int rows, const QModelIndex &index) override;
|
||||
bool removeRows(int position, int rows, const QModelIndex &index) override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
const QVector<payload_t> &getPayloads() const;
|
||||
|
||||
private:
|
||||
QVector<payload_t> payloads;
|
||||
};
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class QPayloadWidget; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class QPayloadWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QPayloadWidget(QWidget *parent = nullptr);
|
||||
explicit QPayloadWidget(TegraRcmGUI *parent = nullptr);
|
||||
std::string tmp_string;
|
||||
const QVector<payload_t> &getPayloads() const { return m_payloadModel->getPayloads(); }
|
||||
|
||||
private:
|
||||
Ui::QPayloadWidget *ui;
|
||||
PayloadModel *m_payloadModel;
|
||||
QFileSystemModel *m_fsModel;
|
||||
TegraRcmGUI *parent;
|
||||
QKourou *m_kourou;
|
||||
Kourou *m_device;
|
||||
qint64 payloadBtnStatusLbl_time = 0;
|
||||
bool payloadBtnLock = false;
|
||||
|
||||
bool addFavorite(QString name, QString path);
|
||||
bool readFavoritesFromFile();
|
||||
bool writeFavoritesToFile();
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void on_deviceStateChange();
|
||||
|
||||
private slots:
|
||||
void on_browsePayloadBtn_clicked();
|
||||
void on_injectPayloadBtn_clicked();
|
||||
void on_addFavoriteBtn_clicked();
|
||||
void on_deleteFavoriteBtn_clicked();
|
||||
void on_autoInject_toggled();
|
||||
void payloadBtnStatusTimer();
|
||||
|
||||
void on_payload_path_textChanged(const QString &arg1);
|
||||
|
||||
void on_payload_tableView_doubleClicked(const QModelIndex &index);
|
||||
|
||||
signals:
|
||||
void error(int);
|
||||
};
|
||||
|
||||
#endif // QPAYLOADWIDGET_H
|
||||
|
|
287
qpayload.ui
287
qpayload.ui
|
@ -1,22 +1,285 @@
|
|||
<ui version="4.0" >
|
||||
<author></author>
|
||||
<comment></comment>
|
||||
<exportmacro></exportmacro>
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form" >
|
||||
<property name="geometry" >
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QPayloadWidget</class>
|
||||
<widget class="QWidget" name="QPayloadWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
<width>496</width>
|
||||
<height>380</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<widget class="QTableView" name="payload_tableView">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>150</y>
|
||||
<width>360</width>
|
||||
<height>145</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
<property name="defaultDropAction">
|
||||
<enum>Qt::MoveAction</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QFrame" name="payloadFrame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>35</y>
|
||||
<width>421</width>
|
||||
<height>81</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">
|
||||
</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<widget class="QPushButton" name="browsePayloadBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>340</x>
|
||||
<y>10</y>
|
||||
<width>71</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>10</y>
|
||||
<width>50</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";
|
||||
color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Path:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>250</x>
|
||||
<y>50</y>
|
||||
<width>81</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";
|
||||
color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto inject:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>340</x>
|
||||
<y>40</y>
|
||||
<width>71</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout"/>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="injectPayloadBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>40</y>
|
||||
<width>101</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>INJECT PAYLOAD</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="payload_path">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>55</x>
|
||||
<y>10</y>
|
||||
<width>281</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="payloadBtnStatusLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>120</x>
|
||||
<y>45</y>
|
||||
<width>131</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QLabel" name="payloadPathLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>15</y>
|
||||
<width>131</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 11pt "Calibri";
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Payload selection:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="addFavoriteBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>390</x>
|
||||
<y>150</y>
|
||||
<width>31</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="qresources.qrc">
|
||||
<normaloff>:/res/add.ico</normaloff>:/res/add.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="deleteFavoriteBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>390</x>
|
||||
<y>190</y>
|
||||
<width>31</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="qresources.qrc">
|
||||
<normaloff>:/res/delete.ico</normaloff>:/res/delete.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="favoritesLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>130</y>
|
||||
<width>120</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 11pt "Calibri";
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Favorites:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<zorder>payload_tableView</zorder>
|
||||
<zorder>payloadFrame</zorder>
|
||||
<zorder>addFavoriteBtn</zorder>
|
||||
<zorder>deleteFavoriteBtn</zorder>
|
||||
<zorder>favoritesLbl</zorder>
|
||||
<zorder>payloadPathLbl</zorder>
|
||||
</widget>
|
||||
<pixmapfunction></pixmapfunction>
|
||||
<resources>
|
||||
<include location="qresources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
|
|
|
@ -1,2 +1,17 @@
|
|||
<!DOCTYPE RCC>
|
||||
<RCC version="1.0"/>
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file alias="ariane_bin">ariane/out/ariane.bin</file>
|
||||
<file>res/switch_logo_off.png</file>
|
||||
<file>res/switch_logo_on.png</file>
|
||||
<file>res/QTabWidget.qss</file>
|
||||
<file>res/QPushButton.qss</file>
|
||||
<file>res/QLabel_title01.qss</file>
|
||||
<file>res/QTableView.qss</file>
|
||||
<file>res/QFrame_box01.qss</file>
|
||||
<file>res/QMainWindow.qss</file>
|
||||
<file>res/QFrame_titleBar.qss</file>
|
||||
<file>res/QFrame_box02.qss</file>
|
||||
<file>res/delete.ico</file>
|
||||
<file>res/add.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
21
qtools.ui
21
qtools.ui
|
@ -1,9 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<author/>
|
||||
<comment/>
|
||||
<exportmacro/>
|
||||
<class>qTools</class>
|
||||
<widget name="qTools" class="QWidget">
|
||||
<widget class="QWidget" name="qTools">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
|
@ -15,7 +13,20 @@
|
|||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>50</x>
|
||||
<y>30</y>
|
||||
<width>47</width>
|
||||
<height>14</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<pixmapfunction/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
134
qutils.cpp
134
qutils.cpp
|
@ -1,5 +1,6 @@
|
|||
#include "qutils.h"
|
||||
|
||||
|
||||
QString FileDialog(QWidget *parent, fdMode mode, const QString& defaultName)
|
||||
{
|
||||
QFileDialog fd(parent);
|
||||
|
@ -21,3 +22,136 @@ QString FileDialog(QWidget *parent, fdMode mode, const QString& defaultName)
|
|||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
QString GetReadableSize(qint64 bytes)
|
||||
{
|
||||
return QLocale().formattedDataSize(bytes);
|
||||
}
|
||||
|
||||
Switch::Switch(bool initial_state, int width, QBrush brush, QWidget *parent) : QAbstractButton(parent),
|
||||
_height(16),
|
||||
_opacity(0.000),
|
||||
_switch(initial_state),
|
||||
_margin(3),
|
||||
_thumb("#d5d5d5"),
|
||||
_width(width),
|
||||
_anim(new QPropertyAnimation(this, "offset", this))
|
||||
{
|
||||
if (!initial_state)
|
||||
{
|
||||
setOffset(_height / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
setOffset(_width - _height);
|
||||
_thumb = brush;
|
||||
}
|
||||
_y = _height / 2;
|
||||
setBrush(brush);
|
||||
}
|
||||
|
||||
Switch::Switch(const QBrush &brush, QWidget *parent) : QAbstractButton(parent),
|
||||
_height(16),
|
||||
_switch(false),
|
||||
_opacity(0.000),
|
||||
_margin(3),
|
||||
_thumb("#d5d5d5"),
|
||||
_anim(new QPropertyAnimation(this, "offset", this))
|
||||
{
|
||||
setOffset(_height / 2);
|
||||
_y = _height / 2;
|
||||
setBrush(brush);
|
||||
}
|
||||
|
||||
void Switch::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
p.setPen(Qt::NoPen);
|
||||
if (isEnabled()) {
|
||||
p.setBrush(_switch ? brush() : Qt::black);
|
||||
p.setOpacity(_switch ? 0.5 : 0.38);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
p.drawRoundedRect(QRect(_margin, _margin, _width - 2 * _margin, height() - 2 * _margin), 8.0, 8.0);
|
||||
p.setBrush(_thumb);
|
||||
p.setOpacity(1.0);
|
||||
p.drawEllipse(QRectF(offset() - (_height / 2), _y - (_height / 2), height(), height()));
|
||||
|
||||
} else {
|
||||
p.setBrush(Qt::black);
|
||||
p.setOpacity(0.12);
|
||||
p.drawRoundedRect(QRect(_margin, _margin, _width - 2 * _margin, height() - 2 * _margin), 8.0, 8.0);
|
||||
p.setOpacity(1.0);
|
||||
p.setBrush(QColor("#BDBDBD"));
|
||||
p.drawEllipse(QRectF(offset() - (_height / 2), _y - (_height / 2), height(), height()));
|
||||
}
|
||||
}
|
||||
|
||||
void Switch::toggle(bool state)
|
||||
{
|
||||
int toffset = offset();
|
||||
_switch = _switch ? false : true;
|
||||
_thumb = _switch ? _brush : QBrush("#d5d5d5");
|
||||
if (_switch) {
|
||||
_anim->setStartValue(_height / 2);
|
||||
_anim->setEndValue(_width - _height);
|
||||
_anim->setDuration(120);
|
||||
_anim->start();
|
||||
} else {
|
||||
_anim->setStartValue(offset());
|
||||
_anim->setEndValue(_height / 2);
|
||||
_anim->setDuration(120);
|
||||
_anim->start();
|
||||
}
|
||||
}
|
||||
|
||||
void Switch::mouseReleaseEvent(QMouseEvent *e) {
|
||||
if (e->button() & Qt::LeftButton) {
|
||||
toggle(_switch);
|
||||
}
|
||||
QAbstractButton::mouseReleaseEvent(e);
|
||||
}
|
||||
|
||||
void Switch::enterEvent(QEvent *e) {
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
QAbstractButton::enterEvent(e);
|
||||
}
|
||||
|
||||
QSize Switch::sizeHint() const {
|
||||
return QSize(2 * (_height + _margin), _height + 2 * _margin);
|
||||
}
|
||||
|
||||
QString GetStyleSheetFromResFile(QString qss_file)
|
||||
{
|
||||
QFile File(qss_file);
|
||||
File.open(QFile::ReadOnly);
|
||||
QString StyleSheet = QLatin1String(File.readAll());
|
||||
File.close();
|
||||
return StyleSheet;
|
||||
}
|
||||
|
||||
|
||||
MoveWindowWidget::MoveWindowWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void MoveWindowWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter painter(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
|
||||
}
|
||||
|
||||
void MoveWindowWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
startPos = event->pos();
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void MoveWindowWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QPoint delta = event->pos() - startPos;
|
||||
QWidget * w = window();
|
||||
if(w)
|
||||
w->move(w->pos() + delta);
|
||||
QWidget::mouseMoveEvent(event);
|
||||
}
|
||||
|
|
88
qutils.h
88
qutils.h
|
@ -5,9 +5,97 @@
|
|||
#include <QFileDialog>
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
#include <QLocale>
|
||||
#include <QtWidgets>
|
||||
|
||||
|
||||
enum fdMode { open_file, save_as };
|
||||
|
||||
QString FileDialog(QWidget *parent, fdMode mode, const QString& defaultName = "");
|
||||
QString GetReadableSize(qint64 bytes);
|
||||
QString GetStyleSheetFromResFile(QString qss_file);
|
||||
|
||||
class Switch : public QAbstractButton {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int offset READ offset WRITE setOffset)
|
||||
Q_PROPERTY(QBrush brush READ brush WRITE setBrush)
|
||||
|
||||
public:
|
||||
Switch(bool initial_state, int width, QBrush brush = QBrush("#009688"), QWidget* parent = nullptr);
|
||||
Switch(const QBrush& brush, QWidget* parent = nullptr);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
QBrush brush() const {
|
||||
return _brush;
|
||||
}
|
||||
void setBrush(const QBrush &brsh) {
|
||||
_brush = brsh;
|
||||
}
|
||||
|
||||
int offset() const {
|
||||
return _x;
|
||||
}
|
||||
void setOffset(int o) {
|
||||
_x = o;
|
||||
update();
|
||||
}
|
||||
|
||||
bool isActive() { return _switch; }
|
||||
void setState(bool value) { _switch = value; }
|
||||
void toggle(bool state);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
void mouseReleaseEvent(QMouseEvent*) override;
|
||||
void enterEvent(QEvent*) override;
|
||||
|
||||
private:
|
||||
bool _switch;
|
||||
qreal _opacity;
|
||||
int _x, _y, _height, _margin, _width;
|
||||
QBrush _thumb, _track, _brush;
|
||||
QPropertyAnimation *_anim = nullptr;
|
||||
};
|
||||
|
||||
|
||||
class AnimatedLabel : public QLabel
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor)
|
||||
|
||||
public:
|
||||
AnimatedLabel(QWidget *parent = 0)
|
||||
{
|
||||
}
|
||||
void setColor (QColor color){
|
||||
setStyleSheet(QString(
|
||||
"qproperty-alignment: 'AlignVCenter | AlignRight';"
|
||||
"background-color: rgba(%1, %2, %3, 200);"
|
||||
"color: rgb(0, 0, 0);"
|
||||
"border-top-left-radius: 20px; "
|
||||
"border-bottom-left-radius: 20px; "
|
||||
"padding: 10px;").arg(color.red()).arg(color.green()).arg(color.blue()));
|
||||
}
|
||||
QColor color(){
|
||||
return Qt::black; // getter is not really needed for now
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class MoveWindowWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MoveWindowWidget(QWidget *parent = nullptr);
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
private:
|
||||
QPoint startPos;
|
||||
};
|
||||
|
||||
#endif // QUTILS_H
|
||||
|
|
11
rcm_device.h
11
rcm_device.h
|
@ -1,11 +0,0 @@
|
|||
#ifndef RCMDEVICE_H
|
||||
#define RCMDEVICE_H
|
||||
|
||||
|
||||
class RcmDevice
|
||||
{
|
||||
public:
|
||||
RcmDevice();
|
||||
};
|
||||
|
||||
#endif // RCMDEVICE_H
|
|
@ -9,4 +9,4 @@ QLabel
|
|||
border-radius: 0px;
|
||||
font: 10pt "Calibri";
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@ QFrame
|
|||
QLabel
|
||||
{
|
||||
border-radius: 0px;
|
||||
font: 10pt "Calibri";
|
||||
color: rgb(255, 255, 255);
|
||||
font: 10pt "Calibri";
|
||||
background-color: rgb(41, 41, 41);
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
QLineEdit
|
||||
{
|
||||
|
@ -18,4 +19,9 @@ QLineEdit
|
|||
font: 9pt "Calibri";
|
||||
border-radius: 2px;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
}
|
||||
QToolTip
|
||||
{
|
||||
background-color: rgb(30, 30, 30);
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
QFrame
|
||||
{
|
||||
border-radius: 10px;
|
||||
background-color: rgb(0, 150, 136);
|
||||
border-color: rgb(0, 0, 0);
|
||||
}
|
||||
QLabel
|
||||
{
|
||||
font: 75 9pt "Calibri";
|
||||
color: rgb(255, 255, 255);
|
||||
border-radius: 10px;
|
||||
background-color: rgb(0, 150, 136);
|
||||
border-color: rgb(0, 0, 0);
|
||||
}
|
|
@ -2,4 +2,17 @@ QMainWindow
|
|||
{
|
||||
background-color: rgb(30, 30, 30);
|
||||
border-radius: 10px;
|
||||
}
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
QStatusBar
|
||||
{
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
QToolTip
|
||||
{
|
||||
background-color: rgb(30, 30, 30);
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
QMessageBox QLabel {
|
||||
color: rgb(0, 0, 0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
QPushButton
|
||||
{
|
||||
background-color: rgb(0, 150, 136);
|
||||
color: rgb(255, 255, 255);
|
||||
border-radius: 10px;
|
||||
}
|
||||
QPushButton:pressed
|
||||
{
|
||||
color: rgb(0, 0, 0);
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
QPushButton:hover
|
||||
{
|
||||
color: rgb(255, 255, 255);
|
||||
background-color: rgb(150, 35, 0);
|
||||
}
|
||||
|
|
@ -1,26 +1,37 @@
|
|||
QTabWidget::pane {
|
||||
border-radius:10px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
QTabWidget::tab-bar
|
||||
QTabWidget::pane
|
||||
{
|
||||
left: 10px;
|
||||
}
|
||||
QTabBar::tab {
|
||||
border-radius:10px;
|
||||
background-color: rgb(60, 60, 60);
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
QTabWidget::tab-bar
|
||||
{
|
||||
left: 10px;
|
||||
}
|
||||
QTabBar::tab
|
||||
{
|
||||
color: rgb(255, 255, 255);
|
||||
|
||||
border: 0px;
|
||||
border-top-left-radius: 6px; /* For rounded corners */
|
||||
border-top-right-radius: 6px;
|
||||
min-width: 8ex;
|
||||
min-width: 10ex;
|
||||
padding: 6px; /* Padding inside each tab */
|
||||
margin-left: 4px; /* Margins among the tabs */
|
||||
margin-right: 4px;
|
||||
background-color: rgb(213, 213, 213);
|
||||
font: 75 9pt "Calibri";
|
||||
color: rgb(0, 0, 0);
|
||||
font: 75 10pt "MS Shell Dlg 2";
|
||||
color: rgb(255, 255, 255);
|
||||
border-bottom: 2px solid grey;
|
||||
}
|
||||
QTabBar::tab:selected {
|
||||
border-bottom: 2px solid white;
|
||||
}
|
||||
QLabel
|
||||
{
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
QToolTip
|
||||
{
|
||||
background-color: rgb(30, 30, 30);
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
QMessageBox QLabel {
|
||||
color: rgb(0, 0, 0);
|
||||
}
|
||||
|
||||
QTabBar::tab:selected {
|
||||
background-color: rgb(0, 150, 136);
|
||||
border-color: grey;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
QTableView
|
||||
{
|
||||
border-radius: 10px;
|
||||
alternate-background-color: rgb(188, 188, 188);
|
||||
background: rgb(240, 240, 240);
|
||||
selection-background-color: rgb(150, 0, 83);
|
||||
}
|
346
tegrarcmgui.cpp
346
tegrarcmgui.cpp
|
@ -1,15 +1,361 @@
|
|||
#include "tegrarcmgui.h"
|
||||
#include "ui_tegrarcmgui.h"
|
||||
#include "qutils.h"
|
||||
#include <QPoint>
|
||||
|
||||
QMouseEvent MouseLeftButtonEvent(QEvent::MouseButtonPress, QPoint(0,0), Qt::LeftButton, nullptr, nullptr);
|
||||
|
||||
TegraRcmGUI * TegraRcmGUI::m_instance;
|
||||
static void KUSB_API HotPlugEventCallback(KHOT_HANDLE Handle, KLST_DEVINFO_HANDLE DeviceInfo, KLST_SYNC_FLAG flag)
|
||||
{
|
||||
Q_ASSERT(TegraRcmGUI::hasInstance());
|
||||
if (DeviceInfo == nullptr || (DeviceInfo->Common.Vid != RCM_VID && DeviceInfo->Common.Pid != RCM_PID))
|
||||
return;
|
||||
|
||||
if (flag == KLST_SYNC_FLAG_ADDED)
|
||||
TegraRcmGUI::instance()->emit sign_hotPlugEvent(true, DeviceInfo);
|
||||
else if (flag == KLST_SYNC_FLAG_REMOVED)
|
||||
TegraRcmGUI::instance()->emit sign_hotPlugEvent(false, DeviceInfo);
|
||||
|
||||
}
|
||||
|
||||
TegraRcmGUI::TegraRcmGUI(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::TegraRcmGUI)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Set a static instance to handle hotplug callback
|
||||
Q_ASSERT(!hasInstance());
|
||||
m_instance = this;
|
||||
|
||||
// Init acces to builtin resources
|
||||
Q_INIT_RESOURCE(qresources);
|
||||
|
||||
// Tray icon init
|
||||
trayIcon = new QSystemTrayIcon;
|
||||
trayIcon->setIcon(switchOffIcon);
|
||||
trayIcon->setVisible(true);
|
||||
connect(trayIcon, &QSystemTrayIcon::activated, this, &TegraRcmGUI::trayIconActivated);
|
||||
trayIconMenu = trayIcon->contextMenu();
|
||||
|
||||
// Load settings
|
||||
userSettings = new QSettings("nx", "TegraRcmGUI");
|
||||
|
||||
// Create a qKourou instance to invoke Kourou methods (asynchronously) using signals and slots
|
||||
m_kourou = new QKourou(this, &m_device, this);
|
||||
|
||||
m_kourou->autoLaunchAriane = userSettings->value("autoAriane").toBool();
|
||||
m_kourou->autoInjectPayload = userSettings->value("autoInject").toBool();
|
||||
|
||||
// Load builtin Ariane payload
|
||||
QFile file(":/ariane_bin");
|
||||
if (file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
m_kourou->ariane_bin = file.readAll();
|
||||
file.close();
|
||||
}
|
||||
|
||||
// Init device at startup (in a concurrent thread)
|
||||
QtConcurrent::run(m_kourou, &QKourou::initDevice, true, nullptr);
|
||||
|
||||
// Set the USB hotplug event
|
||||
qRegisterMetaType<KLST_DEVINFO_HANDLE>("KLST_DEVINFO_HANDLE");
|
||||
QObject::connect(this, SIGNAL(sign_hotPlugEvent(bool, KLST_DEVINFO_HANDLE)), this, SLOT(hotPlugEvent(bool, KLST_DEVINFO_HANDLE)));
|
||||
KHOT_PARAMS hotParams;
|
||||
memset(&hotParams, 0, sizeof(hotParams));
|
||||
hotParams.OnHotPlug = HotPlugEventCallback;
|
||||
hotParams.Flags = KHOT_FLAG_NONE;
|
||||
HotK_Init(&m_hotHandle, &hotParams);
|
||||
|
||||
// Set timers
|
||||
QTimer *devInfoTimer = new QTimer(this);
|
||||
connect(devInfoTimer, SIGNAL(timeout()), this, SLOT(deviceInfoTimer()));
|
||||
devInfoTimer->start(60000*5); // Every 5 minutes
|
||||
QTimer *pushTimer = new QTimer(this);
|
||||
connect(pushTimer, SIGNAL(timeout()), this, SLOT(pushTimer()));
|
||||
pushTimer->start(1000); // Every minute
|
||||
|
||||
|
||||
/// GUI inits
|
||||
// Set stylesheets
|
||||
this->setStyleSheet(GetStyleSheetFromResFile(":/res/QMainWindow.qss"));
|
||||
ui->statusbar->setStyleSheet(GetStyleSheetFromResFile(":/res/QMainWindow.qss"));
|
||||
ui->tabWidget->setStyleSheet(GetStyleSheetFromResFile(":/res/QTabWidget.qss"));
|
||||
ui->titleBarFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_titleBar.qss"));
|
||||
ui->statusBoxFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_box01.qss"));
|
||||
ui->deviceInfoBoxFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_box01.qss"));
|
||||
|
||||
// Init tabs
|
||||
ui->tabWidget->tabBar()->setCursor(Qt::PointingHandCursor);
|
||||
ui->push_layout->setAlignment(Qt::AlignTop);
|
||||
ui->pushLayoutWidget->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
payloadTab = new QPayloadWidget(this);
|
||||
ui->tabWidget->addTab(payloadTab, tr("PAYLOAD"));
|
||||
toolsTab = new qTools(this);
|
||||
ui->tabWidget->addTab(toolsTab, tr("TOOLS"));
|
||||
|
||||
ui->closeAppBtn->setCursor(Qt::PointingHandCursor);
|
||||
connect(ui->closeAppBtn, SIGNAL(clicked()), this, SLOT(close()));
|
||||
|
||||
clearDeviceInfo();
|
||||
Switch *_switch = new Switch(m_kourou->autoLaunchAriane ? true : false, 52);
|
||||
ui->verticalLayout->addWidget(_switch);
|
||||
connect(_switch, SIGNAL(clicked(bool)), this, SLOT(on_autoLaunchAriane_toggled(bool)));
|
||||
|
||||
ui->centralwidget->setFixedSize(680, 400);
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
TegraRcmGUI::~TegraRcmGUI()
|
||||
{
|
||||
if (m_hotHandle != nullptr)
|
||||
HotK_Free(m_hotHandle);
|
||||
|
||||
delete trayIcon;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void TegraRcmGUI::hotPlugEvent(bool added, KLST_DEVINFO_HANDLE deviceInfo)
|
||||
{
|
||||
if (added)
|
||||
QtConcurrent::run(m_kourou, &QKourou::initDevice, true, deviceInfo);
|
||||
else
|
||||
{
|
||||
m_device.disconnect();
|
||||
on_deviceStateChange();
|
||||
}
|
||||
}
|
||||
|
||||
void TegraRcmGUI::deviceInfoTimer()
|
||||
{
|
||||
if (m_device.arianeIsReady())
|
||||
QtConcurrent::run(m_kourou, &QKourou::getDeviceInfo);
|
||||
}
|
||||
|
||||
void TegraRcmGUI::on_deviceStateChange()
|
||||
{
|
||||
ui->devStatusLbl_2->setText(m_device.getStatus() == CONNECTED ? tr("CONNECTED") : tr("DISCONNECTED"));
|
||||
ui->devStatusFrame->setStyleSheet(m_device.getStatus() == CONNECTED ? statusOnStyleSht : statusOffStyleSht);
|
||||
ui->rcmStatusLbl_2->setText(m_device.rcmIsReady() ? tr("READY") : tr("OFF"));
|
||||
QString arianeStatus;
|
||||
if (m_kourou->arianeIsLoading)
|
||||
arianeStatus.append(tr("LOADING"));
|
||||
else if (m_device.arianeIsReady())
|
||||
arianeStatus.append(tr("READY"));
|
||||
else
|
||||
arianeStatus.append(tr("OFF"));
|
||||
ui->arianeStatusLbl_2->setText(arianeStatus);
|
||||
ui->rcmStatusFrame->setStyleSheet(m_device.rcmIsReady() ? statusOnStyleSht : statusOffStyleSht);
|
||||
ui->arianeStatusFrame->setStyleSheet(m_device.arianeIsReady() ? statusOnStyleSht : statusOffStyleSht);
|
||||
if (!m_device.arianeIsReady())
|
||||
clearDeviceInfo();
|
||||
|
||||
if (m_device.rcmIsReady() || m_device.arianeIsReady())
|
||||
trayIcon->setIcon(switchOnIcon);
|
||||
else
|
||||
trayIcon->setIcon(switchOffIcon);
|
||||
|
||||
payloadTab->on_deviceStateChange();
|
||||
|
||||
}
|
||||
|
||||
void TegraRcmGUI::on_autoLaunchAriane_toggled(bool value)
|
||||
{
|
||||
m_kourou->autoLaunchAriane = !m_kourou->autoLaunchAriane;
|
||||
userSettings->setValue("autoAriane", m_kourou->autoLaunchAriane);
|
||||
|
||||
if (m_device.rcmIsReady() && m_kourou->autoLaunchAriane)
|
||||
QtConcurrent::run(m_kourou, &QKourou::initDevice, true, nullptr);
|
||||
}
|
||||
|
||||
bool TegraRcmGUI::enableWidget(QWidget *widget, bool enable)
|
||||
{
|
||||
widget->setEnabled(enable);
|
||||
}
|
||||
|
||||
void TegraRcmGUI::clearDeviceInfo()
|
||||
{
|
||||
ui->deviceInfoFrame->setStyleSheet(statusOffStyleSht);
|
||||
ui->deviceInfoLbl->setStyleSheet(statusOffStyleSht);
|
||||
ui->batteryLevel->hide();
|
||||
ui->batteryLevel->setValue(0);
|
||||
ui->burntFusesLbl2->setText("");
|
||||
ui->sdfsLbl2->setText("");
|
||||
ui->sdfsLbl2->setText("");
|
||||
ui->fsTotSizeLbl2->setText("");
|
||||
ui->fsFreeSpaceLbl2->setText("");
|
||||
if (!m_kourou->autoLaunchAriane)
|
||||
{
|
||||
ui->batteryLbl->hide();
|
||||
ui->burntFusesLbl1->hide();
|
||||
ui->sdfsLbl1->hide();
|
||||
ui->fsTotSizeLbl1->hide();
|
||||
ui->fsFreeSpaceLbl1->hide();
|
||||
ui->devInfoDisableLbl->show();
|
||||
}
|
||||
else ui->devInfoDisableLbl->hide();
|
||||
}
|
||||
|
||||
void TegraRcmGUI::on_deviceInfo_received(UC_DeviceInfo di)
|
||||
{
|
||||
ui->batteryLbl->show();
|
||||
ui->burntFusesLbl1->show();
|
||||
ui->sdfsLbl1->show();
|
||||
ui->fsTotSizeLbl1->show();
|
||||
ui->fsFreeSpaceLbl1->show();
|
||||
ui->devInfoDisableLbl->hide();
|
||||
ui->deviceInfoLbl->setStyleSheet(GetStyleSheetFromResFile(":/res/QLabel_title01.qss"));
|
||||
ui->batteryLevel->show();
|
||||
ui->batteryLevel->setValue(int(di.battery_capacity));
|
||||
ui->burntFusesLbl2->setText(QString().asprintf("%u", di.burnt_fuses));
|
||||
ui->sdfsLbl2->setText(QString().asprintf("%s", di.sdmmc_initialized ? "Yes" : "No"));
|
||||
if (di.sdmmc_initialized)
|
||||
{
|
||||
QString fs;
|
||||
if (di.emmc_fs_type == FS_FAT32) fs.append("FAT32");
|
||||
else if (di.emmc_fs_type == FS_EXFAT) fs.append("exFAT");
|
||||
else fs.append("UNKNOWN");
|
||||
ui->sdfsLbl2->setText(fs);
|
||||
|
||||
qint64 fs_size = 0x200 * (qint64)di.emmc_fs_cl_size * ((qint64)di.emmc_fs_last_cl + 1);
|
||||
qint64 fs_free_space = 0x200 * (qint64)di.emmc_fs_cl_size * (qint64)di.emmc_fs_free_cl;
|
||||
ui->fsTotSizeLbl2->setText(GetReadableSize(fs_size));
|
||||
ui->fsFreeSpaceLbl2->setText(GetReadableSize(fs_free_space));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->sdfsLbl2->setText("N/A");
|
||||
ui->fsTotSizeLbl2->setText("N/A");
|
||||
ui->fsFreeSpaceLbl2->setText("N/A");
|
||||
}
|
||||
}
|
||||
|
||||
void TegraRcmGUI::error(int error)
|
||||
{
|
||||
QMessageBox::critical(this, "Error", QString().asprintf("Error %d", error));
|
||||
}
|
||||
|
||||
void TegraRcmGUI::pushMessage(QString message)
|
||||
{
|
||||
AnimatedLabel *push = new AnimatedLabel;
|
||||
QPropertyAnimation *animation = new QPropertyAnimation(push, "color");
|
||||
animation->setDuration(800);
|
||||
animation->setStartValue(QColor(0, 150, 136));
|
||||
animation->setEndValue(QColor(202, 202, 202));
|
||||
push->setText(message);
|
||||
push->setMinimumHeight(40);
|
||||
push->setMaximumHeight(80);
|
||||
ui->push_layout->addWidget(push);
|
||||
animation->start();
|
||||
|
||||
push_ts.push_back(QDateTime::currentSecsSinceEpoch());
|
||||
}
|
||||
|
||||
void TegraRcmGUI::pushTimer()
|
||||
{
|
||||
|
||||
qint64 now = QDateTime::currentSecsSinceEpoch();
|
||||
|
||||
if (tsToDeleteCount && push_ts.count() == 0)
|
||||
{
|
||||
for (int i(0); i < tsToDeleteCount; i++)
|
||||
ui->pushLayoutWidget->findChildren<QLabel*>().at(i)->deleteLater();
|
||||
|
||||
tsToDeleteCount = 0;
|
||||
}
|
||||
|
||||
if (!push_ts.size())
|
||||
return;
|
||||
|
||||
int i(0);
|
||||
int j(0);
|
||||
for (qint64 ts : push_ts)
|
||||
{
|
||||
if (now > ts + 5)
|
||||
{
|
||||
auto item = ui->pushLayoutWidget->findChildren<QLabel*>().at(j + tsToDeleteCount);
|
||||
QPropertyAnimation *animation = new QPropertyAnimation(item, "geometry");
|
||||
//QPropertyAnimation *animation = new QPropertyAnimation(item, "offset");
|
||||
animation->setDuration(500);
|
||||
int r = item->pos().y() + item->height() - 10;
|
||||
if (lastTsToDelete)
|
||||
r -= lastTsToDelete * item->pos().y();
|
||||
animation->setStartValue(QRect(item->pos().x(), item->pos().y(), ui->pushLayoutWidget->width(), r));
|
||||
animation->setEndValue(QRect(ui->pushLayoutWidget->width(), item->pos().y(), ui->pushLayoutWidget->width(), r));
|
||||
animation->start();
|
||||
lastTsToDelete = ts;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
push_ts.erase(push_ts.begin(), push_ts.begin() + i);
|
||||
tsToDeleteCount += i;
|
||||
}
|
||||
|
||||
void TegraRcmGUI::on_Kourou_finished(int res)
|
||||
{
|
||||
if (res == AUTO_INJECT || res == PAYLOAD_INJECT)
|
||||
pushMessage(tr("Payload successfully injected"));
|
||||
}
|
||||
|
||||
void TegraRcmGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
|
||||
{
|
||||
|
||||
int t;
|
||||
switch (reason) {
|
||||
case QSystemTrayIcon::Trigger:
|
||||
t = 0;
|
||||
break;
|
||||
case QSystemTrayIcon::DoubleClick:
|
||||
t = 0;
|
||||
break;
|
||||
case QSystemTrayIcon::MiddleClick:
|
||||
t = 0;
|
||||
break;
|
||||
case QSystemTrayIcon::Context:
|
||||
drawTrayContextMenu();
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void TegraRcmGUI::drawTrayContextMenu()
|
||||
{
|
||||
//trayIconMenu->addAction("Exit",this,SLOT(close()));
|
||||
QString menu_ss = "QMenu::item {"
|
||||
"padding: 4px 20px 4px 4px;"
|
||||
"}"
|
||||
"QMenu::item:selected {"
|
||||
"background-color: rgb(0, 85, 127);"
|
||||
"color: rgb(255, 255, 255);"
|
||||
"}";
|
||||
|
||||
|
||||
QMenu *menu = new QMenu;
|
||||
menu->setStyleSheet(menu_ss);
|
||||
menu->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
menu->addAction("Exit",this,SLOT(close()));
|
||||
|
||||
QMenu *fav_menu = new QMenu;
|
||||
fav_menu->setStyleSheet(menu_ss);
|
||||
fav_menu->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
fav_menu->setTitle("Favorites");
|
||||
|
||||
for (payload_t payload : payloadTab->getPayloads())
|
||||
{
|
||||
QMenu *p_menu = new QMenu;
|
||||
p_menu->setStyleSheet(menu_ss);
|
||||
p_menu->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
p_menu->setTitle(payload.name);
|
||||
fav_menu->addMenu(p_menu);
|
||||
}
|
||||
|
||||
menu->addMenu(fav_menu);
|
||||
|
||||
trayIcon->setContextMenu(menu);
|
||||
trayIcon->contextMenu()->popup(QCursor::pos());
|
||||
}
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
#ifndef TEGRARCMGUI_H
|
||||
#define TEGRARCMGUI_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QtWidgets>
|
||||
#include <QSettings>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include "qpayload.h"
|
||||
#include "qtools.h"
|
||||
#include "kourou/kourou.h"
|
||||
#include "kourou/usb_command.h"
|
||||
#include "qkourou.h"
|
||||
|
||||
class QPayloadWidget;
|
||||
class QKourou;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class TegraRcmGUI; }
|
||||
|
@ -9,13 +19,66 @@ QT_END_NAMESPACE
|
|||
|
||||
class TegraRcmGUI : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
static TegraRcmGUI* m_instance;
|
||||
public:
|
||||
TegraRcmGUI(QWidget *parent = nullptr);
|
||||
~TegraRcmGUI();
|
||||
static bool hasInstance() { return m_instance; }
|
||||
static TegraRcmGUI * instance() {
|
||||
if (!m_instance) m_instance = new TegraRcmGUI;
|
||||
return m_instance;
|
||||
}
|
||||
QSettings *userSettings;
|
||||
QSettings *userPayloads;
|
||||
Kourou m_device;
|
||||
QKourou *m_kourou;
|
||||
QPayloadWidget *payloadTab;
|
||||
qTools *toolsTab;
|
||||
bool enableWidget(QWidget *widget, bool enable);
|
||||
|
||||
private slots:
|
||||
void on_deviceInfo_received(UC_DeviceInfo di);
|
||||
void on_autoLaunchAriane_toggled(bool value);
|
||||
void pushTimer();
|
||||
void on_Kourou_finished(int res);
|
||||
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
|
||||
|
||||
public slots:
|
||||
void hotPlugEvent(bool added, KLST_DEVINFO_HANDLE deviceInfo);
|
||||
void deviceInfoTimer();
|
||||
void error(int error);
|
||||
void on_deviceStateChange();
|
||||
void pushMessage(QString message);
|
||||
|
||||
signals:
|
||||
void sign_hotPlugEvent(bool added, KLST_DEVINFO_HANDLE);
|
||||
|
||||
private:
|
||||
Ui::TegraRcmGUI *ui;
|
||||
KHOT_HANDLE m_hotHandle = nullptr;
|
||||
|
||||
bool m_ready = false;
|
||||
std::string tmp_string;
|
||||
QVector<qint64> push_ts;
|
||||
int tsToDeleteCount = 0;
|
||||
qint64 lastTsToDelete = 0;
|
||||
|
||||
const QIcon switchOnIcon = QIcon(":/res/switch_logo_on.png");
|
||||
const QIcon switchOffIcon = QIcon(":/res/switch_logo_off.png");
|
||||
QSystemTrayIcon *trayIcon;
|
||||
QMenu *trayIconMenu;
|
||||
void drawTrayContextMenu();
|
||||
|
||||
void clearDeviceInfo();
|
||||
};
|
||||
|
||||
const QString statusOnStyleSht( "QFrame{border-radius: 10px; background-color: rgb(0, 150, 136); border-color: rgb(0, 0, 0);}"
|
||||
"QLabel{font: 75 9pt \"Calibri\"; color: rgb(255, 255, 255);}");
|
||||
const QString statusOffStyleSht("QFrame{border-radius: 10px; background-color: rgb(213, 213, 213); border-color: rgb(0, 0, 0);}"
|
||||
"QLabel{font: 75 9pt \"Calibri\"; color: rgb(0, 0, 0);}");
|
||||
const QString statusOffRedStyleSht("QFrame{border-radius: 10px; background-color: rgb(150, 35, 0); border-color: rgb(0, 0, 0);}"
|
||||
"QLabel{font: 75 9pt \"Calibri\"; color: rgb(255, 255, 255);}");
|
||||
|
||||
#endif // TEGRARCMGUI_H
|
||||
|
|
642
tegrarcmgui.ui
642
tegrarcmgui.ui
|
@ -6,17 +6,649 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
<width>677</width>
|
||||
<height>435</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>TegraRcmGUI</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget"/>
|
||||
<widget class="QMenuBar" name="menubar"/>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>190</x>
|
||||
<y>30</y>
|
||||
<width>481</width>
|
||||
<height>371</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QFrame" name="devStatusFrame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>30</y>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-radius: 10px;
|
||||
background-color: rgb(0, 150, 136);
|
||||
border-color: rgb(0, 0, 0);
|
||||
QLabel{font: 75 11pt "Calibri"; color: rgb(255, 255, 255);}
|
||||
|
||||
</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="devStatusLbl_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>-1</x>
|
||||
<y>0</y>
|
||||
<width>101</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QFrame" name="rcmStatusFrame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>120</x>
|
||||
<y>55</y>
|
||||
<width>50</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-radius: 10px;
|
||||
background-color: rgb(0, 150, 136);
|
||||
border-color: rgb(0, 0, 0);
|
||||
QLabel{font: 75 11pt "Calibri"; color: rgb(255, 255, 255);}
|
||||
|
||||
</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="rcmStatusLbl_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>50</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QFrame" name="arianeStatusFrame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>120</x>
|
||||
<y>105</y>
|
||||
<width>50</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-radius: 10px;
|
||||
background-color: rgb(0, 150, 136);
|
||||
border-color: rgb(0, 0, 0);
|
||||
QLabel{font: 75 11pt "Calibri"; color: rgb(255, 255, 255);}
|
||||
|
||||
</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="arianeStatusLbl_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>50</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>120</x>
|
||||
<y>80</y>
|
||||
<width>51</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="devInfoBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>150</y>
|
||||
<width>171</width>
|
||||
<height>251</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";
|
||||
border:0px;
|
||||
QLabel{
|
||||
background-color: rgb(255, 255, 255);
|
||||
color: rgb(37, 37, 38);
|
||||
}</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QFrame" name="deviceInfoBoxFrame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>10</y>
|
||||
<width>171</width>
|
||||
<height>241</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="batteryLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>20</y>
|
||||
<width>81</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";
|
||||
QLabel{
|
||||
background-color: rgb(255, 255, 255);
|
||||
color: rgb(37, 37, 38);
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Battery charge:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="burntFusesLbl1">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>40</y>
|
||||
<width>81</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Burnt fuses:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="sdfsLbl1">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>60</y>
|
||||
<width>81</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SD Filesystem:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="fsTotSizeLbl1">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>80</y>
|
||||
<width>81</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>FS Total size:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="fsFreeSpaceLbl1">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>100</y>
|
||||
<width>81</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>FS Free space:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="fsFreeSpaceLbl2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>100</x>
|
||||
<y>100</y>
|
||||
<width>71</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="fsTotSizeLbl2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>100</x>
|
||||
<y>80</y>
|
||||
<width>71</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="sdfsLbl2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>100</x>
|
||||
<y>60</y>
|
||||
<width>71</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="burntFusesLbl2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>100</x>
|
||||
<y>40</y>
|
||||
<width>71</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QProgressBar" name="batteryLevel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>100</x>
|
||||
<y>20</y>
|
||||
<width>51</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QProgressBar {
|
||||
border: 2px solid grey;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
QProgressBar::chunk {
|
||||
background-color: #009688;
|
||||
width: 1px;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
<property name="format">
|
||||
<string>%p%</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="devInfoDisableLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>151</width>
|
||||
<height>221</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Ariane autoboot
|
||||
to display device info</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QFrame" name="deviceInfoFrame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>150</y>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">
|
||||
|
||||
</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="deviceInfoLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(255, 255, 255);
|
||||
font: 9pt "Calibri";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>DEVICE INFO</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QFrame" name="statusBoxFrame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>40</y>
|
||||
<width>171</width>
|
||||
<height>101</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="rcmStatusLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>15</y>
|
||||
<width>101</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>RCM status:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="autoLaunchArianeLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>40</y>
|
||||
<width>101</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Ariane autoboot:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="arianeStatusLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>65</y>
|
||||
<width>101</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Calibri";
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Ariane status:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="pushLayoutWidget" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>390</x>
|
||||
<y>20</y>
|
||||
<width>291</width>
|
||||
<height>381</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgba(0,0,0,0)</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="pushLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="push_layout"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QFrame" name="titleBarFrame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>-1</x>
|
||||
<y>0</y>
|
||||
<width>685</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<widget class="QLabel" name="titleBarLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>0</y>
|
||||
<width>151</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TegraRcmGUI v3.0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="closeAppBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>655</x>
|
||||
<y>0</y>
|
||||
<width>21</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="MoveWindowWidget" name="moveWindowWidget" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>-1</x>
|
||||
<y>0</y>
|
||||
<width>651</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<zorder>statusBoxFrame</zorder>
|
||||
<zorder>tabWidget</zorder>
|
||||
<zorder>devStatusFrame</zorder>
|
||||
<zorder>rcmStatusFrame</zorder>
|
||||
<zorder>arianeStatusFrame</zorder>
|
||||
<zorder>verticalLayoutWidget</zorder>
|
||||
<zorder>devInfoBox</zorder>
|
||||
<zorder>deviceInfoFrame</zorder>
|
||||
<zorder>pushLayoutWidget</zorder>
|
||||
<zorder>titleBarFrame</zorder>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>MoveWindowWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qutils.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
35
types.h
35
types.h
|
@ -1,4 +1,39 @@
|
|||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
using u64 = std::uint64_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u8 = std::uint8_t;
|
||||
using s64 = std::int64_t;
|
||||
using s32 = std::int32_t;
|
||||
using s16 = std::int16_t;
|
||||
using s8 = std::int8_t;
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::array;
|
||||
|
||||
template<typename T, size_t ARR_SIZE>
|
||||
size_t array_countof(T(&)[ARR_SIZE]) { return ARR_SIZE; }
|
||||
|
||||
template<typename T, typename Y>
|
||||
T align_up(const T n, const Y align)
|
||||
{
|
||||
const T alignm1 = align - 1;
|
||||
return (n + alignm1) & (~alignm1);
|
||||
}
|
||||
|
||||
template<typename T, typename Y>
|
||||
T align_down(const T n, const Y align)
|
||||
{
|
||||
const T alignm1 = align - 1;
|
||||
return n & (~alignm1);
|
||||
}
|
||||
|
||||
#endif // TYPES_H
|
||||
|
|
Loading…
Add table
Reference in a new issue