Ajout du de l'interface avec le bootloader PIC32
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
#include "BootloaderProtocol.h"
|
||||
#include "PICUploader.h"
|
||||
|
||||
|
||||
|
||||
|
||||
CBootloaderProtocol::CBootloaderProtocol(QObject *parent) : QObject(parent)
|
||||
{
|
||||
mCRCEngine.InitTable();
|
||||
}
|
||||
|
||||
CBootloaderProtocol::~CBootloaderProtocol()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CBootloaderProtocol::BootloaderProtocolInit()
|
||||
{
|
||||
BootloaderProtocolResetStateMachine();
|
||||
}
|
||||
|
||||
int CBootloaderProtocol::BootloaderProtocolResetStateMachine()
|
||||
{
|
||||
mBootloaderDataSize = 0;
|
||||
mBootloaderHeader = 0;
|
||||
mBootloaderBufPtr = 0;
|
||||
mBootloaderDataBuffer.clear();
|
||||
mBootloaderCommand = 0;
|
||||
mBootloaderCRC = 0;
|
||||
mBootloaderComputedCRC = CRC_START_32;
|
||||
mBootloaderState = RxHeader1;
|
||||
mBootloaderDataCtr = 0;
|
||||
|
||||
}
|
||||
|
||||
int CBootloaderProtocol::BooloaderProtocolRxFrame(QByteArray Frame)
|
||||
{
|
||||
for(int i = 0; i < Frame.size(); i++)
|
||||
{
|
||||
BootloaderProtocolStateMachine(Frame.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
void CBootloaderProtocol::BootloaderProtocolStateMachine(unsigned char Data)
|
||||
{
|
||||
|
||||
switch(mBootloaderState)
|
||||
{
|
||||
case Initialization: //Reset all pointers and data...
|
||||
{
|
||||
mBootloaderDataSize = 0;
|
||||
mBootloaderBufPtr = 0;
|
||||
mBootloaderDataBuffer.clear();
|
||||
mBootloaderCommand = 0;
|
||||
mBootloaderCRC = 0;
|
||||
mBootloaderComputedCRC = CRC_START_32;
|
||||
mBootloaderState = RxHeader1;
|
||||
break;
|
||||
}
|
||||
case RxHeader1: //Wait for data header...
|
||||
{
|
||||
mBootloaderHeader += Data; //0xDE
|
||||
mBootloaderComputedCRC = mCRCEngine.UpdateCRC32(mBootloaderComputedCRC,Data);
|
||||
|
||||
if(Data == BOOTLOADER_FRAME_HEADER_1)
|
||||
{
|
||||
mBootloaderState = RxHeader2;
|
||||
}
|
||||
else
|
||||
{
|
||||
BootloaderProtocolResetStateMachine();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case RxHeader2: //Wait for data header...
|
||||
{
|
||||
mBootloaderHeader <<= 8;
|
||||
mBootloaderHeader += Data; //0xAD
|
||||
mBootloaderComputedCRC = mCRCEngine.UpdateCRC32(mBootloaderComputedCRC,Data);
|
||||
|
||||
if(Data == BOOTLOADER_FRAME_HEADER_2)
|
||||
{
|
||||
mBootloaderState = RxHeader3;
|
||||
}
|
||||
else
|
||||
{
|
||||
BootloaderProtocolResetStateMachine();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RxHeader3: //Wait for data header...
|
||||
{
|
||||
mBootloaderHeader <<= 8;
|
||||
mBootloaderHeader += Data; //0xBE
|
||||
mBootloaderComputedCRC = mCRCEngine.UpdateCRC32(mBootloaderComputedCRC,Data);
|
||||
|
||||
if(Data == BOOTLOADER_FRAME_HEADER_3)
|
||||
{
|
||||
mBootloaderState = RxHeader4;
|
||||
}
|
||||
else
|
||||
{
|
||||
BootloaderProtocolResetStateMachine();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RxHeader4: //Wait for data header...
|
||||
{
|
||||
mBootloaderHeader <<= 8;
|
||||
mBootloaderHeader += Data; //0xEF
|
||||
mBootloaderComputedCRC = mCRCEngine.UpdateCRC32(mBootloaderComputedCRC,Data);
|
||||
|
||||
if(mBootloaderHeader != BOOTLOADER_FRAME_HEADER)
|
||||
{
|
||||
//TODO, send NACK?
|
||||
BootloaderProtocolResetStateMachine();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
mBootloaderState = RxCmd;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case RxCmd:
|
||||
{
|
||||
mBootloaderCommand = Data;
|
||||
mBootloaderState = RxPayloadSize1;
|
||||
mBootloaderComputedCRC = mCRCEngine.UpdateCRC32(mBootloaderComputedCRC,Data);
|
||||
break;
|
||||
}
|
||||
case RxPayloadSize1:
|
||||
{
|
||||
mBootloaderDataSize = Data;
|
||||
mBootloaderState = RxPayloadSize2;
|
||||
mBootloaderComputedCRC = mCRCEngine.UpdateCRC32(mBootloaderComputedCRC,Data);
|
||||
break;
|
||||
}
|
||||
case RxPayloadSize2:
|
||||
{
|
||||
mBootloaderDataSize <<= 8;
|
||||
mBootloaderDataSize += Data;
|
||||
|
||||
mBootloaderState = RxPayloadSize3;
|
||||
mBootloaderComputedCRC = mCRCEngine.UpdateCRC32(mBootloaderComputedCRC,Data);
|
||||
break;
|
||||
}
|
||||
case RxPayloadSize3:
|
||||
{
|
||||
mBootloaderDataSize <<= 8;
|
||||
mBootloaderDataSize += Data;
|
||||
mBootloaderComputedCRC = mCRCEngine.UpdateCRC32(mBootloaderComputedCRC,Data);
|
||||
|
||||
mBootloaderState = RxPayloadSize4;
|
||||
break;
|
||||
}
|
||||
case RxPayloadSize4:
|
||||
{
|
||||
mBootloaderDataSize <<= 8;
|
||||
mBootloaderDataSize += Data;
|
||||
mBootloaderComputedCRC = mCRCEngine.UpdateCRC32(mBootloaderComputedCRC,Data);
|
||||
|
||||
if(mBootloaderDataSize > MAX_BOOTLOADER_PAYLOAD_SIZE)
|
||||
{
|
||||
//TODO, send NACK?
|
||||
BootloaderProtocolResetStateMachine();
|
||||
break;
|
||||
}
|
||||
|
||||
mBootloaderState = RxPayload;
|
||||
break;
|
||||
}
|
||||
case RxPayload: //Data size
|
||||
{
|
||||
mBootloaderDataBuffer.append(Data);
|
||||
mBootloaderDataCtr++;
|
||||
mBootloaderComputedCRC = mCRCEngine.UpdateCRC32(mBootloaderComputedCRC,Data);
|
||||
|
||||
if(mBootloaderDataCtr == mBootloaderDataSize)
|
||||
{
|
||||
mBootloaderState = RxCRC1;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case RxCRC1: //Data size
|
||||
{
|
||||
mBootloaderCRC = Data;
|
||||
mBootloaderState = RxCRC2;
|
||||
break;
|
||||
}
|
||||
case RxCRC2: //Data size
|
||||
{
|
||||
mBootloaderCRC <<= 8;
|
||||
mBootloaderCRC += Data;
|
||||
mBootloaderState = RxCRC3;
|
||||
break;
|
||||
}
|
||||
case RxCRC3: //Data size
|
||||
{
|
||||
mBootloaderCRC <<= 8;
|
||||
mBootloaderCRC += Data;
|
||||
mBootloaderState = RxCRC4;
|
||||
break;
|
||||
}
|
||||
case RxCRC4: //Data size
|
||||
{
|
||||
mBootloaderCRC <<= 8;
|
||||
mBootloaderCRC += Data;
|
||||
|
||||
mBootloaderComputedCRC ^= 0xffffffffL;
|
||||
//if(mBootloaderCRC == 0xBAADCAFE)
|
||||
if(mBootloaderCRC == mBootloaderComputedCRC)
|
||||
{
|
||||
mProgramHandle->BootloaderRxCmd(mBootloaderCommand,mBootloaderDataBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("Bootloader Protocol bad CRC...");
|
||||
}
|
||||
|
||||
BootloaderProtocolResetStateMachine();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
BootloaderProtocolResetStateMachine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray CBootloaderProtocol::BootloaderProtocolGetFrame(char Cmd, QByteArray Data)
|
||||
{
|
||||
QByteArray Frame;
|
||||
Frame.clear();
|
||||
|
||||
// Header
|
||||
Frame.append(BOOTLOADER_FRAME_HEADER_1);
|
||||
Frame.append(BOOTLOADER_FRAME_HEADER_2);
|
||||
Frame.append(BOOTLOADER_FRAME_HEADER_3);
|
||||
Frame.append(BOOTLOADER_FRAME_HEADER_4);
|
||||
|
||||
//Cmd
|
||||
Frame.append(Cmd);
|
||||
|
||||
//Size
|
||||
unsigned int Size = Data.size();
|
||||
|
||||
char nibble = (char)((Size >> 24) &0x000000FF);
|
||||
Frame.append(nibble);
|
||||
|
||||
nibble = (char)((Size >> 16) &0x000000FF);
|
||||
Frame.append(nibble);
|
||||
|
||||
nibble = (char)((Size >> 8) &0x000000FF);
|
||||
Frame.append(nibble);
|
||||
|
||||
nibble = (char)(Size &0x000000FF);
|
||||
Frame.append(nibble);
|
||||
|
||||
//Payload
|
||||
Frame.append(Data);
|
||||
|
||||
//CRC
|
||||
unsigned int CRC = mCRCEngine.ComputeCRC32(Frame);
|
||||
|
||||
nibble = (char)((CRC >> 24) &0x000000FF);
|
||||
Frame.append(nibble);
|
||||
|
||||
nibble = (char)((CRC >> 16) &0x000000FF);
|
||||
Frame.append(nibble);
|
||||
|
||||
nibble = (char)((CRC >> 8) &0x000000FF);
|
||||
Frame.append(nibble);
|
||||
|
||||
nibble = (char)(CRC &0x000000FF);
|
||||
Frame.append(nibble);
|
||||
|
||||
/* Frame.append(0xBA);
|
||||
Frame.append(0xAD);
|
||||
Frame.append(0xCA);
|
||||
Frame.append(0xFE);*/
|
||||
|
||||
//Send
|
||||
return Frame;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#ifndef BOOTLOADERPROTOCOL_H
|
||||
#define BOOTLOADERPROTOCOL_H
|
||||
|
||||
#include <QObject>
|
||||
#include "ProtocolDefs.h"
|
||||
#include "CRC32.h"
|
||||
|
||||
class CPICUploader;
|
||||
|
||||
#define BOOTLOADER_FRAME_HEADER 0xDEADBEEF
|
||||
#define BOOTLOADER_FRAME_HEADER_1 0xDE
|
||||
#define BOOTLOADER_FRAME_HEADER_2 0xAD
|
||||
#define BOOTLOADER_FRAME_HEADER_3 0xBE
|
||||
#define BOOTLOADER_FRAME_HEADER_4 0xEF
|
||||
#define MAX_BOOTLOADER_PAYLOAD_SIZE 200
|
||||
|
||||
|
||||
|
||||
enum eProtocolBootloaderStates
|
||||
{
|
||||
Initialization,
|
||||
RxHeader1,
|
||||
RxHeader2,
|
||||
RxHeader3,
|
||||
RxHeader4,
|
||||
RxCmd,
|
||||
RxPayloadSize1,
|
||||
RxPayloadSize2,
|
||||
RxPayloadSize3,
|
||||
RxPayloadSize4,
|
||||
RxPayload,
|
||||
RxCRC1,
|
||||
RxCRC2,
|
||||
RxCRC3,
|
||||
RxCRC4
|
||||
};
|
||||
|
||||
class CBootloaderProtocol : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CBootloaderProtocol(QObject *parent = 0);
|
||||
~CBootloaderProtocol();
|
||||
|
||||
int BootloaderProtocolInit();
|
||||
int BootloaderProtocolResetStateMachine();
|
||||
|
||||
int BooloaderProtocolRxFrame(QByteArray Frame);
|
||||
void BootloaderProtocolStateMachine(unsigned char data);
|
||||
|
||||
QByteArray BootloaderProtocolGetFrame(char Cmd, QByteArray Data);
|
||||
|
||||
|
||||
|
||||
|
||||
CPICUploader *mProgramHandle;
|
||||
|
||||
|
||||
private:
|
||||
unsigned int mBootloaderHeader;
|
||||
unsigned int mBootloaderDataSize;
|
||||
unsigned int mBootloaderDataCtr;
|
||||
unsigned int mBootloaderBufPtr;
|
||||
unsigned int mBootloaderCRC;
|
||||
unsigned int mBootloaderComputedCRC;
|
||||
QByteArray mBootloaderDataBuffer;
|
||||
unsigned char mBootloaderCommand;
|
||||
unsigned char mBootloaderState;
|
||||
|
||||
CCRC32 mCRCEngine;
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
#endif // BOOTLOADERPROTOCOL_H
|
||||
@@ -1,10 +1,13 @@
|
||||
#include "HexFile.h"
|
||||
#include <QTextStream>
|
||||
#include <QMessageBox>
|
||||
#include "CRC32.h"
|
||||
|
||||
#define USE_BIG_RECORDS
|
||||
#define MAX_RECORDS_IN_BIG_RECORDS 512 //16 bytes by record, 512 bytes by row --> 16 rows / big record
|
||||
|
||||
|
||||
|
||||
CHexFile::CHexFile(void)
|
||||
{
|
||||
mFileOpened = false;
|
||||
@@ -13,8 +16,9 @@ CHexFile::CHexFile(void)
|
||||
mHighAddress = 0;
|
||||
mDiscardedRecords = 0;
|
||||
mTotalParsedRecords = 0;
|
||||
mFirmwareCRC = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
CHexFile::~CHexFile(void)
|
||||
{
|
||||
@@ -28,6 +32,8 @@ int CHexFile::CloseOpenedHexFile()
|
||||
for(int i = 0; i < mRecordsList.size(); i++)
|
||||
delete mRecordsList.at(i);
|
||||
|
||||
mRecordsList.clear();
|
||||
|
||||
mFileOpened = false;
|
||||
mFileParsed = false;
|
||||
mHexfileHandle = 0;
|
||||
@@ -35,6 +41,8 @@ int CHexFile::CloseOpenedHexFile()
|
||||
mHighAddress = 0;
|
||||
mDiscardedRecords = 0;
|
||||
mTotalParsedRecords = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHexFile::OpenDataFile(QString FilePath, bool CloseIfAlreadyParsed)
|
||||
@@ -75,8 +83,11 @@ int CHexFile::OpenDataFile(QString FilePath, bool CloseIfAlreadyParsed)
|
||||
|
||||
return ParseData();
|
||||
|
||||
mHexfileHandle->close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
int CHexFile::ParseData(void)
|
||||
{
|
||||
if(!mFileOpened)
|
||||
@@ -170,6 +181,8 @@ int CHexFile::ParseData(void)
|
||||
int RecordCount;
|
||||
CHexRecord *TempRecordPtr;
|
||||
CHexRecord *BigRecord = new CHexRecord;
|
||||
CCRC32 Crc32Engine;
|
||||
|
||||
|
||||
TempRecordPtr = TempList.at(0);
|
||||
CurAddress = TempRecordPtr->GetStartAddress();
|
||||
@@ -215,15 +228,63 @@ int CHexFile::ParseData(void)
|
||||
delete TempList[i];
|
||||
}
|
||||
|
||||
for(i = 0; i < mRecordsList.size(); i++)
|
||||
// for(i = 0; i < mRecordsList.size(); i++)
|
||||
// {
|
||||
// mFirmwareDataSize += mRecordsList.at(i)->GetRecordSizeInBytes();
|
||||
// }
|
||||
|
||||
FilterRecords(0x1D004000,0x1D07FFFF);
|
||||
|
||||
QByteArray RawShit = GetRawData(false);
|
||||
|
||||
mFirmwareDataSize = RawShit.size();
|
||||
|
||||
unsigned int testcrc = CRC_START_32;
|
||||
for(unsigned int i = 0; i < mFirmwareDataSize; i++)
|
||||
{
|
||||
mFirmwareDataSize += mRecordsList.at(i)->GetRecordSizeInBytes();
|
||||
testcrc = Crc32Engine.UpdateCRC32(testcrc,RawShit[i]);
|
||||
}
|
||||
testcrc ^= 0xffffffffL;
|
||||
|
||||
mFirmwareCRC = Crc32Engine.ComputeCRC32((const unsigned char *)RawShit.data(),RawShit.size());
|
||||
|
||||
mFileParsed = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHexFile::FilterRecords(unsigned int StartAddress, unsigned int EndAddress)
|
||||
{
|
||||
if(mRecordsList.isEmpty() == true)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
int i = 0;
|
||||
while(done == false)
|
||||
{
|
||||
if(mRecordsList.at(i)->GetStartAddress() < StartAddress ||
|
||||
mRecordsList.at(i)->GetStartAddress() > EndAddress)
|
||||
{
|
||||
//Record is outside filter area, delete it...
|
||||
delete mRecordsList.at(i);
|
||||
mRecordsList.removeAt(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
if(i == mRecordsList.size())
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int CHexFile::GetNBRecords(void)
|
||||
{
|
||||
// return mRecordsTableSize;
|
||||
@@ -237,6 +298,11 @@ unsigned long CHexFile::GetFileSize(void)
|
||||
return mHexFileSize;
|
||||
}
|
||||
|
||||
unsigned int CHexFile::GetDataCRC32()
|
||||
{
|
||||
return mFirmwareCRC;
|
||||
}
|
||||
|
||||
CHexRecord * CHexFile::GetRecord(int RecordIndex, int &Status)
|
||||
{
|
||||
|
||||
@@ -252,7 +318,63 @@ CHexRecord * CHexFile::GetRecord(int RecordIndex, int &Status)
|
||||
return mRecordPtr;
|
||||
}
|
||||
|
||||
QByteArray CHexFile::GetRawData(bool IncludeHeader)
|
||||
{
|
||||
QByteArray Data;
|
||||
Data.clear();
|
||||
|
||||
|
||||
if(IncludeHeader)
|
||||
{
|
||||
QDataStream Strm(&Data,QIODevice::WriteOnly);
|
||||
|
||||
//Header
|
||||
Strm << HEX_FILE_HEADER_CODE;
|
||||
//Flags
|
||||
Strm << (int)0x0000; //TODO: Manage that
|
||||
//Nb Records
|
||||
Strm << GetNBRecords();
|
||||
//Firmware size
|
||||
Strm << GetFirmwareSize();
|
||||
//Version
|
||||
Strm << (int)0x00; //TODO: Manage that
|
||||
//CRC32
|
||||
Strm << GetDataCRC32();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
for(int i = 0; i < mRecordsList.size(); i++)
|
||||
{
|
||||
Data.append(mRecordsList.at(i)->GetRecord());
|
||||
}
|
||||
|
||||
return Data;
|
||||
}
|
||||
|
||||
|
||||
QString CHexFile::GetHexFileInfoString()
|
||||
{
|
||||
|
||||
QString string;
|
||||
string.clear();
|
||||
|
||||
if(HexDataValid() == false)
|
||||
return QString("No file loaded\n");
|
||||
|
||||
for(int i = 0; i < mRecordsList.size(); i++)
|
||||
{
|
||||
CHexRecord *rec = mRecordsList.at(i);
|
||||
unsigned int StartAddress = rec->GetStartAddress();
|
||||
unsigned int Size = rec->GetRecordSizeInBytes();
|
||||
unsigned int EndAddress = StartAddress + Size;
|
||||
string.append(QString("Record %1: Start = [0x%2], Length = [%3], End = 0x%4\n").arg(i).arg(StartAddress,0,16).arg(Size).arg(EndAddress,0,16));
|
||||
}
|
||||
string.prepend("-------------------------------------------------------------\n");
|
||||
string.append("-------------------------------------------------------------\n");
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <QList>
|
||||
#include <QFile>
|
||||
|
||||
#define HEX_FILE_HEADER_CODE (int)0xBAADBEEF
|
||||
|
||||
|
||||
|
||||
class CHexFile
|
||||
{
|
||||
@@ -21,14 +24,18 @@ public:
|
||||
~CHexFile(void);
|
||||
|
||||
int OpenDataFile(QString FilePath, bool CloseIfAlreadyParsed = true);
|
||||
int CloseDataFile();
|
||||
int CloseOpenedHexFile();
|
||||
int ParseData(void);
|
||||
unsigned int GetNBRecords(void);
|
||||
unsigned long GetFileSize(void);
|
||||
unsigned long GetFirmwareSize(void){return mFirmwareDataSize;}
|
||||
unsigned int GetFirmwareSize(void){return mFirmwareDataSize;}
|
||||
unsigned int GetDataCRC32(void);
|
||||
bool HexFileLoaded(void){return mFileOpened;}
|
||||
bool HexDataValid(void){return mFileParsed;}
|
||||
unsigned long GetTotalParsedRecords(void){return mTotalParsedRecords;}
|
||||
QByteArray GetRawData(bool IncludeHeader = true);
|
||||
int FilterRecords(unsigned int StartAddress, unsigned int EndAddress);
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +43,8 @@ public:
|
||||
unsigned long mDiscardedRecords;
|
||||
unsigned long mTotalParsedRecords;
|
||||
|
||||
QString GetHexFileInfoString();
|
||||
|
||||
private:
|
||||
QFile *mHexfileHandle;
|
||||
bool mFileOpened;
|
||||
@@ -47,7 +56,8 @@ private:
|
||||
unsigned int mRecordsTableSize;
|
||||
unsigned int mHighAddress;
|
||||
unsigned long mHexFileSize;
|
||||
unsigned long mFirmwareDataSize;
|
||||
unsigned int mFirmwareDataSize;
|
||||
unsigned int mFirmwareCRC;
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "HexRecord.h"
|
||||
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDataStream>
|
||||
CHexRecord::CHexRecord(void)
|
||||
{
|
||||
mRecordData = NULL;
|
||||
@@ -175,3 +175,24 @@ CHexRecord& CHexRecord::operator = (const CHexRecord &rhs)
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
QByteArray CHexRecord::GetRecord()
|
||||
{
|
||||
QByteArray Record;
|
||||
Record.clear();
|
||||
QDataStream Strm(&Record,QIODevice::WriteOnly);
|
||||
|
||||
|
||||
|
||||
//Header
|
||||
Strm << HEX_RECORD_HEADER;
|
||||
//Size
|
||||
Strm << GetRecordSizeInBytes();
|
||||
//Address
|
||||
Strm << GetStartAddress();
|
||||
//Data
|
||||
Record.append(mRecordData);
|
||||
|
||||
|
||||
return Record;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <QByteArray>
|
||||
|
||||
#define IGNORE_ALL_FF_RECORDS
|
||||
|
||||
#define HEX_RECORD_HEADER (int)0xDEADBEEF
|
||||
class CHexRecord
|
||||
{
|
||||
public:
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
unsigned int GetRecordSizeInBytes(void){return mRecordData.size();}
|
||||
unsigned int GetRecordType(void){return mRecordType;}
|
||||
unsigned int AppendRecord(CHexRecord *RecordToAppend);
|
||||
QByteArray GetRecord();
|
||||
|
||||
CHexRecord& operator=(const CHexRecord &rhs);
|
||||
|
||||
|
||||
@@ -1,30 +1,916 @@
|
||||
#include "PICUploader.h"
|
||||
#include "GlobalDefine.h"
|
||||
#include <QHostAddress>
|
||||
#include <QtEndian>
|
||||
|
||||
|
||||
CPICUploader::CPICUploader(CPICUploaderGui *Gui)
|
||||
{
|
||||
mPICUploaderGui = Gui;
|
||||
mPICUploaderGui->mProgramHandle = this;
|
||||
|
||||
connect(&mBootloaderSocket,SIGNAL(connected()),this,SLOT(BootloaderSocketConnected()));
|
||||
connect(&mBootloaderSocket,SIGNAL(disconnected()),this,SLOT(BootloaderSocketDisconnected()));
|
||||
connect(&mBootloaderSocket,SIGNAL(readyRead()),this,SLOT(BootloaderDataAvailable()));
|
||||
connect(&mBootloaderSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(BootloaderSocketError(QAbstractSocket::SocketError)));
|
||||
|
||||
mBootloaderProtocol.mProgramHandle = this;
|
||||
}
|
||||
|
||||
|
||||
int CPICUploader::Start()
|
||||
{
|
||||
mBootloaderProtocol.BootloaderProtocolInit();
|
||||
ResetBooloaderInterfaceStateMachine();
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
|
||||
int CPICUploader::OpenHexFileRequest(QString FilePath)
|
||||
{
|
||||
if(mHexFile.HexFileLoaded() == true)
|
||||
{
|
||||
mHexFile.CloseOpenedHexFile();
|
||||
}
|
||||
|
||||
int ret = mHexFile.OpenDataFile(FilePath);
|
||||
|
||||
if(ret == 0)
|
||||
return 0;
|
||||
|
||||
QString HexFileStats = QString("HexFileSize: %1\nFirmware Size: %4\nNb analyzed Records: %2\nNb Big Records: %3").arg(mHexFile.GetFileSize()).arg(mHexFile.GetTotalParsedRecords()).arg(mHexFile.GetNBRecords()).arg(mHexFile.GetFirmwareSize());
|
||||
QString HexFileStats = QString("HexFileSize: %1\nFirmware Size: %4\nNb analyzed Records: %2\nNb Big Records: %3\nData CRC32: 0x%5").arg(mHexFile.GetFileSize()).arg(mHexFile.GetTotalParsedRecords()).arg(mHexFile.GetNBRecords()).arg(mHexFile.GetFirmwareSize()).arg(mHexFile.GetDataCRC32(),0,16);
|
||||
|
||||
mPICUploaderGui->SetHexFileStats(HexFileStats);
|
||||
|
||||
|
||||
//HexFileStats << "HexFileSize: " << mHexFile.GetFileSize() << "\n";
|
||||
// HexFileStats <<
|
||||
}
|
||||
|
||||
int CPICUploader::ShowHexFileInfoRequest()
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(mHexFile.GetHexFileInfoString());
|
||||
}
|
||||
|
||||
int CPICUploader::ConnectToBootloader(QString IP)
|
||||
{
|
||||
|
||||
mBootloaderSocket.connectToHost(IP,99);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int CPICUploader::DisconnectFromBootloader()
|
||||
{
|
||||
mBootloaderSocket.disconnectFromHost();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPICUploader::BootloaderSocketConnected()
|
||||
{
|
||||
mPICUploaderGui->UploaderSocketConnected();
|
||||
mPICUploaderGui->AddTextToLogScreen("Socket Connected");
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_BOOTLOADER_CONNECTED_CMD);
|
||||
}
|
||||
|
||||
void CPICUploader::BootloaderSocketDisconnected()
|
||||
{
|
||||
mPICUploaderGui->UploaderSocketDisconnected();
|
||||
mPICUploaderGui->AddTextToLogScreen("Socket Disconnected");
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_BOOTLOADER_DISCONNECTED_CMD);
|
||||
}
|
||||
|
||||
void CPICUploader::BootloaderDataAvailable()
|
||||
{
|
||||
|
||||
QByteArray Data = mBootloaderSocket.readAll();
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Recevied %1 bytes from bootloader").arg(Data.size()));
|
||||
mBootloaderProtocol.BooloaderProtocolRxFrame(Data);
|
||||
|
||||
}
|
||||
|
||||
void CPICUploader::BootloaderSocketError(QAbstractSocket::SocketError Error)
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Socket error %1 in PICUploader").arg(Error));
|
||||
}
|
||||
|
||||
int CPICUploader::SendSingleCmdRequest(int CmdID)
|
||||
{
|
||||
QByteArray Frame = mBootloaderProtocol.BootloaderProtocolGetFrame(CmdID,QByteArray());
|
||||
mBootloaderSocket.write(Frame);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int CPICUploader::SendCmdRequest(int CmdID, QByteArray Data)
|
||||
{
|
||||
QByteArray Frame = mBootloaderProtocol.BootloaderProtocolGetFrame(CmdID,Data);
|
||||
mBootloaderSocket.write(Frame);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int CPICUploader::GuiEvent(int EventID, void *Data)
|
||||
{
|
||||
switch(EventID)
|
||||
{
|
||||
case CPICUploaderGui::UPLOADER_GUI_HEARTBEAT_BTN_CLICK_EVENT:
|
||||
{
|
||||
SendSingleCmdRequest(BOOTLOADER_HEARTBEAT_REQUEST);
|
||||
break;
|
||||
}
|
||||
case CPICUploaderGui::UPLOADER_GUI_FLASH_ERASE_BTN_CLICK_EVENT:
|
||||
{
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_ERASE_FLASH_GUI_CMD);
|
||||
break;
|
||||
}
|
||||
case CPICUploaderGui::UPLOADER_GUI_INIT_UPLOAD_BTN_CLICK_EVENT:
|
||||
{
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_START_UPLOAD_GUI_CMD);
|
||||
break;
|
||||
}
|
||||
case CPICUploaderGui::UPLOADER_GUI_SEND_DATA_CHUNK_BTN_CLICK_EVENT:
|
||||
{
|
||||
SendSingleCmdRequest(BOOTLOADER_SEND_DATA_CHUNK_REQUEST);
|
||||
break;
|
||||
}
|
||||
case CPICUploaderGui::UPLOADER_GUI_UPLOAD_FINISHED_BTN_CLICK_EVENT:
|
||||
{
|
||||
SendSingleCmdRequest(BOOTLOADER_UPLOAD_FINISHED_REQUEST);
|
||||
break;
|
||||
}
|
||||
case CPICUploaderGui::UPLOADER_GUI_EXECUTE_UPGRADE_BTN_CLICK_EVENT:
|
||||
{
|
||||
SendSingleCmdRequest(BOOTLOADER_EXECUTE_UPGRAGE_REQUEST);
|
||||
break;
|
||||
}
|
||||
case CPICUploaderGui::UPLOADER_GUI_ABORT_BTN_CLICK_EVENT:
|
||||
{
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_ABORT_GUI_CMD);
|
||||
break;
|
||||
}
|
||||
case CPICUploaderGui::UPLOADER_GUI_AUTOMATIC_UPDATE_START_BTN_CLICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case CPICUploaderGui::UPLOADER_GUI_GET_STATE_BTN_CLICK_EVENT:
|
||||
{
|
||||
SendSingleCmdRequest(BOOTLOADER_GET_STATE_REQUEST);
|
||||
break;
|
||||
}
|
||||
case CPICUploaderGui::UPLOADER_GUI_CHECK_FLASH_CLICK_EVENT:
|
||||
{
|
||||
SendSingleCmdRequest(BOOTLOADER_CHECK_FLASH_FIRMW_INTEGRITY_REQUEST);
|
||||
break;
|
||||
}
|
||||
case CPICUploaderGui::UPLOADER_GUI_GET_STORED_FIRMWARE_INFO_CLICK_EVENT:
|
||||
{
|
||||
SendSingleCmdRequest(BOOTLOADER_GET_STORED_FIRMWARE_INFO_REQUEST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int CPICUploader::BootloaderRxCmd(int CmdID, QByteArray Data)
|
||||
{
|
||||
switch(CmdID)
|
||||
{
|
||||
case BOOTLOADER_HEARTBEAT_RESPONSE:
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Heartbeat device response: %1").arg((int)Data.at(0)));
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_ERASE_BOOTLOADER_FLASH_RESPONSE:
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Erase flash device response: %1").arg((int)Data.at(0)));
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_ERASE_BOOTLOADER_FLASH_ACK_HOST_CMD,Data.at(0));
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_ERASE_BOOTLOADER_FLASH_RESULT_RESPONSE:
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Erase flash result device response: %1").arg((int)Data.at(0)));
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_ERASE_BOOTLOADER_FLASH_RESULT_HOST_CMD,Data.at(0));
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_INIT_UPLOAD_RESPONSE:
|
||||
{
|
||||
int ChunkSize;
|
||||
quint32 temp = *(int*)Data.mid(1,4).data();
|
||||
qToBigEndian(temp,&ChunkSize);
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Init Upload device response: %1, Chunk Size: %2").arg((int)Data.at(0)).arg(ChunkSize));
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_INIT_UPLOAD_HOST_CMD,(int)Data.at(0),(void*)&ChunkSize);
|
||||
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_GET_STATE_RESPONSE:
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Get State device Response: %1").arg((int)Data.at(0)));
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_READY_FOR_DATA_RESPONSE:
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Ready for data device response: %1").arg((int)Data.at(0)));
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_READY_FOR_DATA_HOST_CMD,(int)Data.at(0));
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_SEND_DATA_CHUNK_RESPONSE:
|
||||
{
|
||||
quint32 temp = *(int*)Data.mid(1,4).data();
|
||||
int Index;
|
||||
qToBigEndian(temp,&Index);
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Send Chunk device response: %1, Index: %2").arg((int)Data.at(0)).arg(Index));
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_SEND_DATA_CHUNK_HOST_CMD,(int)Data.at(0),(void*)&Index);
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_FINISHED_RESPONSE:
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Upload finished device response: %1").arg((int)Data.at(0)));
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_UPLOAD_FINISHED_HOST_CMD,(int)Data.at(0));
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_EXECUTE_UPGRADE_RESPONSE:
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Execute upgrade device response: %1").arg((int)Data.at(0)));
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_EXECUTE_UPGRADE_HOST_CMD,(int)Data.at(0));
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_ABORT_OPERATION_RESPONSE:
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Abort Operation device response: %1").arg((int)Data.at(0)));
|
||||
BootloaderInterfaceStateMachine(BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,BOOTLOADER_UPLOAD_ABORT_OPERATION_HOST_CMD,(int)Data.at(0));
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_CHECK_FLASH_FIRMW_INTEGRITY_RESPONSE:
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Flash integrity check response: %1").arg((int)Data.at(0)));
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_GET_STORED_FIRMWARE_INFO_RESPONSE:
|
||||
{
|
||||
QString FirmwareInfo;
|
||||
FirmwareInfo.clear();
|
||||
|
||||
if(Data.at(0) == 0)
|
||||
{
|
||||
FirmwareInfo = "--------------------------------\nNo firmware stored in SPI flash\n--------------------------------";
|
||||
}
|
||||
else
|
||||
{
|
||||
quint32 FirmwareFlags, NbRecords, FirmwareSize, VersionCode, DataCRC32;
|
||||
|
||||
quint32 temp = *(int*)Data.mid(1,4).data();
|
||||
qToBigEndian(temp,&FirmwareFlags);
|
||||
|
||||
temp = *(int*)Data.mid(5,4).data();
|
||||
qToBigEndian(temp,&NbRecords);
|
||||
|
||||
temp = *(int*)Data.mid(9,4).data();
|
||||
qToBigEndian(temp,&FirmwareSize);
|
||||
|
||||
temp = *(int*)Data.mid(13,4).data();
|
||||
qToBigEndian(temp,&VersionCode);
|
||||
|
||||
temp = *(int*)Data.mid(17,4).data();
|
||||
qToBigEndian(temp,&DataCRC32);
|
||||
|
||||
FirmwareInfo = QString("\n----------------------------------\nStored firmware info:\nFirmware flags: 0x%1\nNb Records: %2\nFirmware Size: %3\nVersion: %4\nData CRC32: 0x%5\n----------------------------------\n")\
|
||||
.arg(FirmwareFlags,0,16).arg(NbRecords).arg(FirmwareSize).arg(VersionCode).arg(DataCRC32,0,16);
|
||||
|
||||
}
|
||||
|
||||
mPICUploaderGui->AddTextToLogScreen(FirmwareInfo);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CPICUploader::BootloaderInterfaceStateMachine(int Event, int Cmd, int CmdParam, void* Data)
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_BOOTLOADER_DISCONNECTED_CMD:
|
||||
{
|
||||
ResetBooloaderInterfaceStateMachine();
|
||||
return RET_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// State machine implementation starts here...
|
||||
|
||||
switch (mBootloaderInterfaceSMState)
|
||||
{
|
||||
case BOOTLOADER_INTERFACE_SM_STANDBY_STATE:
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_SM_TICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_BOOTLOADER_CONNECTED_CMD:
|
||||
{
|
||||
mBootloaderInterfaceSMState = BOOTLOADER_INTERFACE_SM_BOOTLDR_CONNECTED_STATE;
|
||||
mPICUploaderGui->AddTextToLogScreen("[BootloaderSM] Going into CONNECTED state\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_INTERFACE_SM_BOOTLDR_CONNECTED_STATE:
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_SM_TICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_ERASE_FLASH_GUI_CMD:
|
||||
{
|
||||
SendSingleCmdRequest(BOOTLOADER_ERASE_BOOTLOADER_FLASH_REQUEST);
|
||||
mBootloaderInterfaceSMState = BOOTLOADER_INTERFACE_SM_ERASE_FLASH_STATE;
|
||||
mPICUploaderGui->AddTextToLogScreen("[BootloaderSM] Going into ERASE_FLASH state\n");
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_START_FULL_UPDATE_GUI_CMD:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_START_UPLOAD_GUI_CMD:
|
||||
{
|
||||
SendSingleCmdRequest(BOOTLOADER_INIT_UPLOAD_REQUEST);
|
||||
mBootloaderInterfaceSMState = BOOTLOADER_INTERFACE_SM_INIT_UPLOAD_STATE;
|
||||
mPICUploaderGui->AddTextToLogScreen("[BootloaderSM] Going into INIT_UPLOAD state\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_INTERFACE_SM_ERASE_FLASH_STATE:
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_SM_TICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_ERASE_BOOTLOADER_FLASH_ACK_HOST_CMD:
|
||||
{
|
||||
if(CmdParam != BOOTLOADER_FLASH_ERASE_OK)
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen("Flash erase refused from host. Going back to CONNECTED state\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen("Device confirmed erasing flash in progress... \n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_ERASE_BOOTLOADER_FLASH_RESULT_HOST_CMD:
|
||||
{
|
||||
if(CmdParam != BOOTLOADER_FLASH_ERASE_OK)
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen("Flash erase failed. Going back to CONNECTED state\n");
|
||||
mBootloaderInterfaceSMState = BOOTLOADER_INTERFACE_SM_BOOTLDR_CONNECTED_STATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen("Flash erase success. \n");
|
||||
mBootloaderInterfaceSMState = BOOTLOADER_INTERFACE_SM_BOOTLDR_CONNECTED_STATE;
|
||||
mPICUploaderGui->AddTextToLogScreen("[BootloaderSM] Going into CONNECTED state\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_INTERFACE_SM_INIT_UPLOAD_STATE:
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_SM_TICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_INIT_UPLOAD_HOST_CMD:
|
||||
{
|
||||
if(CmdParam == BOOTLOADER_INIT_UPLOAD_SUCCESS)
|
||||
{
|
||||
//Host is in update mode. Load the buffer size and wait for "Ready for data" CMD (stay in the same state)
|
||||
mFirmwareUploadBufferSize = *(int*)Data;
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Init upload accepted by host. Frame size: %1\n").arg(mFirmwareUploadBufferSize));
|
||||
mBootloaderInterfaceSMState = BOOTLOADER_INTERFACE_SM_WAIT_READY_FOR_DATA_FROM_HOST_STATE;
|
||||
mPICUploaderGui->AddTextToLogScreen("[BootloaderSM] Going into READY_FOR_DATA state\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Something's wrong with the host. Abort upload...
|
||||
//TODO: Make the GUI aware of this.
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Init upload refused. Error code: %1. Going back to STANDBY state\n").arg(CmdParam));
|
||||
ResetBooloaderInterfaceStateMachine();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_INTERFACE_SM_WAIT_READY_FOR_DATA_FROM_HOST_STATE:
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_SM_TICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_READY_FOR_DATA_HOST_CMD:
|
||||
{
|
||||
//Host is ready for data. Start the upload state machine
|
||||
mPICUploaderGui->AddTextToLogScreen("Host ready for data. Starting upload\n");
|
||||
BootloaderFirmwareUploadStateMachine(BOOTLOADER_FIRM_UPLD_CMD_EVENT,BOOTLOADER_FIRM_UPLD_INIT_UPLOAD_CMD);
|
||||
mBootloaderInterfaceSMState = BOOTLOADER_INTERFACE_SM_SEND_DATA_STATE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Invalid response from host received int <WAIT READY FOR DATA> state. Response Cmd received: %1. Going back to STANDBY state\n").arg(Cmd));
|
||||
ResetBooloaderInterfaceStateMachine();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_INTERFACE_SM_SEND_DATA_STATE:
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_SM_TICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_SEND_DATA_CHUNK_HOST_CMD:
|
||||
{
|
||||
int Res = BootloaderFirmwareUploadStateMachine(BOOTLOADER_FIRM_UPLD_CMD_EVENT,BOOTLOADER_FIRM_UPLD_CHUNK_RX_RESPONSE_CMD,CmdParam,*(int*)Data);
|
||||
switch(Res)
|
||||
{
|
||||
case BOOTLOADER_FIRM_UPLD_SENDING_RES:
|
||||
{
|
||||
//All is going well.
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_FINISHED_RES:
|
||||
{
|
||||
mBootloaderInterfaceSMState = BOOTLOADER_INTERFACE_SM_DATA_FINISHED_STATE;
|
||||
mPICUploaderGui->AddTextToLogScreen("Bootloader upload state machine uploaded all firmware\n");
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_ERROR_RES:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_TIMEOUT_RES:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_ABORT_RES:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_OK_RES:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_INTERFACE_SM_DATA_FINISHED_STATE:
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_SM_TICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_UPLOAD_BOOTLOADER_CONNECTED_CMD:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_UPLOAD_UPLOAD_FINISHED_HOST_CMD:
|
||||
{
|
||||
mBootloaderInterfaceSMState = BOOTLOADER_INTERFACE_SM_BOOTLDR_CONNECTED_STATE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
//State machine managing firmware packets upload and errors
|
||||
int CPICUploader::BootloaderFirmwareUploadStateMachine(int Event, int Cmd, int CmdResult, int CmdParam)
|
||||
{
|
||||
switch(mBootloaderFirmwareUpldState)
|
||||
{
|
||||
case BOOTLOADER_FIRM_UPLD_STANDBY_STATE:
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_FIRM_UPLD_TICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_FIRM_UPLD_INIT_UPLOAD_CMD:
|
||||
{
|
||||
//TODO: Send First chunk
|
||||
bool Finished;
|
||||
mFirmwareData = mHexFile.GetRawData();
|
||||
SendCmdRequest(BOOTLOADER_SEND_DATA_CHUNK_REQUEST, GetCurDataChunk(Finished));
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Upload SM: Sending first frame (%1)\n").arg(mFirmwareUploadCurFrame));
|
||||
int NbChunks = mFirmwareData.size() / mFirmwareUploadBufferSize;
|
||||
mPICUploaderGui->SetUploadProgressSettings(NbChunks);
|
||||
mPICUploaderGui->ResetProgressBar();
|
||||
if(Finished)
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("That was the last chunk. Going into UPLOAD_FINISHED state\n"));
|
||||
mBootloaderFirmwareUpldState = BOOTLOADER_FIRM_UPLD_FINISHED_STATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mBootloaderFirmwareUpldState = BOOTLOADER_FIRM_UPLD_SEND_CHUNK_STATE;
|
||||
}
|
||||
return BOOTLOADER_FIRM_UPLD_SENDING_RES;
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_ABORT_UPLOAD_CMD:
|
||||
{
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return BOOTLOADER_FIRM_UPLD_ABORT_RES;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
//TODO: Find out what to do with that...
|
||||
return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// case BOOTLOADER_FIRM_UPLD_WAIT_FOR_HOST_READY_STATE:
|
||||
// {
|
||||
// switch(Event)
|
||||
// {
|
||||
// case BOOTLOADER_FIRM_UPLD_TICK_EVENT:
|
||||
// {
|
||||
// return BOOTLOADER_FIRM_UPLD_WAITING_FOR_HOST_RES;
|
||||
// break;
|
||||
// }
|
||||
// case BOOTLOADER_FIRM_UPLD_CMD_EVENT:
|
||||
// {
|
||||
// switch(Cmd)
|
||||
// {
|
||||
// case BOOTLOADER_FIRM_UPLD_INIT_UPLOAD_ACK_CMD:
|
||||
// {
|
||||
// if(CmdResult == BOOTLOADER_INIT_UPLOAD_SUCCESS)
|
||||
// {
|
||||
// //Host is in update mode. Load the buffer size and wait for "Ready for data" CMD (stay in the same state)
|
||||
// mFirmwareUploadBufferSize = CmdParam;
|
||||
// return BOOTLOADER_FIRM_UPLD_WAITING_FOR_HOST_RES;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ResetFirmwareUploadStateMachine();
|
||||
// return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// case BOOTLOADER_FIRM_UPLD_HOST_READY_FOR_DATA_CMD:
|
||||
// {
|
||||
// //Host is ready for data. Send the first chunk and go into next state (send chunk)
|
||||
// //TODO: Send first data chunk
|
||||
// mBootloaderFirmwareUpldState = BOOTLOADER_FIRM_UPLD_SEND_CHUNK_STATE;
|
||||
// return BOOTLOADER_FIRM_UPLD_SENDING_RES;
|
||||
// break;
|
||||
// }
|
||||
// default:
|
||||
// {
|
||||
// return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// break;
|
||||
// }
|
||||
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
case BOOTLOADER_FIRM_UPLD_SEND_CHUNK_STATE:
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_FIRM_UPLD_TICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_FIRM_UPLD_CHUNK_RX_RESPONSE_CMD:
|
||||
{
|
||||
switch(CmdResult)
|
||||
{
|
||||
case BOOTLOADER_CHUNK_TRANSFER_SUCCESS:
|
||||
{
|
||||
if(mFirmwareUploadCurFrame == 700 || mFirmwareUploadCurFrame == 800 || mFirmwareUploadCurFrame == 900)
|
||||
{
|
||||
int toto = 5;
|
||||
}
|
||||
bool Finished = false;
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Upload SM: Sending frame Nb: %1\n").arg(mFirmwareUploadCurFrame));
|
||||
mFirmwareUploadCurFrame++;
|
||||
SendCmdRequest(BOOTLOADER_SEND_DATA_CHUNK_REQUEST, GetCurDataChunk(Finished));
|
||||
mPICUploaderGui->TickProgressBar();
|
||||
if(Finished)
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("That was the last chunk. Going into UPLOAD_FINISHED state\n"));
|
||||
mBootloaderFirmwareUpldState = BOOTLOADER_FIRM_UPLD_FINISHED_STATE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_CHUNK_TRANSFER_ERROR_RESEND:
|
||||
{
|
||||
//TODO: Resend current frame
|
||||
if(mFirmwareUploadCurFrame != CmdParam)
|
||||
{
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Upload of frame %1 failed. and frame index desynchronized (Curframe = %2). Aborting and going to STANDBY mode\n").arg(CmdParam).arg(mFirmwareUploadCurFrame));
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
}
|
||||
bool Finished;
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Upload of frame %1 failed. Trying to resend\n").arg(CmdParam));
|
||||
SendCmdRequest(BOOTLOADER_SEND_DATA_CHUNK_REQUEST, GetCurDataChunk(Finished));
|
||||
//TODO: Manage the number of failed attempts.
|
||||
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_CHUNK_TRANSFER_ERROR_FLASH_FAILURE:
|
||||
{
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_CHUNK_TRANSFER_ERROR_INVALID_CHUNK_INDEX:
|
||||
{
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_CHUNK_TRANSFER_ERROR_FLASH_ERROR:
|
||||
{
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return BOOTLOADER_FIRM_UPLD_SENDING_RES;
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_ABORT_UPLOAD_CMD:
|
||||
{
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return BOOTLOADER_FIRM_UPLD_ABORT_RES;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ResetFirmwareUploadStateMachine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_FINISHED_STATE:
|
||||
{
|
||||
switch(Event)
|
||||
{
|
||||
case BOOTLOADER_FIRM_UPLD_TICK_EVENT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_FIRM_UPLD_CMD_EVENT:
|
||||
{
|
||||
switch(Cmd)
|
||||
{
|
||||
case BOOTLOADER_FIRM_UPLD_CHUNK_RX_RESPONSE_CMD:
|
||||
{switch(CmdResult)
|
||||
{
|
||||
case BOOTLOADER_CHUNK_TRANSFER_SUCCESS:
|
||||
{
|
||||
//TODO: Send upload finished CMD to host
|
||||
|
||||
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Upload of last frame success. Frame Nb %1\n").arg(CmdParam));
|
||||
mPICUploaderGui->TickProgressBar();
|
||||
|
||||
return BOOTLOADER_FIRM_UPLD_FINISHED_RES;
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_CHUNK_TRANSFER_ERROR_RESEND:
|
||||
{
|
||||
//TODO: Resend current frame
|
||||
if(mFirmwareUploadCurFrame != CmdParam)
|
||||
{
|
||||
//TODO: Manage this error... (Abort)
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
}
|
||||
bool Finished;
|
||||
mPICUploaderGui->AddTextToLogScreen(QString("Upload of frame %1 failed. Trying to resend\n").arg(CmdParam));
|
||||
SendCmdRequest(BOOTLOADER_SEND_DATA_CHUNK_REQUEST, GetCurDataChunk(Finished));
|
||||
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_CHUNK_TRANSFER_ERROR_FLASH_FAILURE:
|
||||
{
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_CHUNK_TRANSFER_ERROR_INVALID_CHUNK_INDEX:
|
||||
{
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
break;
|
||||
}
|
||||
case BOOTLOADER_CHUNK_TRANSFER_ERROR_FLASH_ERROR:
|
||||
{
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return BOOTLOADER_FIRM_UPLD_ERROR_RES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ResetFirmwareUploadStateMachine();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ResetFirmwareUploadStateMachine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return BOOTLOADER_FIRM_UPLD_OK_RES;
|
||||
|
||||
}
|
||||
|
||||
int CPICUploader::ResetBooloaderInterfaceStateMachine()
|
||||
{
|
||||
mBootloaderInterfaceSMState = BOOTLOADER_INTERFACE_SM_STANDBY_STATE;
|
||||
mFirmwareUploadBufferSize = 0;
|
||||
mFirmwareUploadCurFrame = 0;
|
||||
ResetFirmwareUploadStateMachine();
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int CPICUploader::ResetFirmwareUploadStateMachine()
|
||||
{
|
||||
mBootloaderFirmwareUpldState = BOOTLOADER_FIRM_UPLD_STANDBY_STATE;
|
||||
mFirmwareData.clear();
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
//Sends current data chunk based on mFirmwareUploadCurFrame and mFirmwareUploadBufferSize.
|
||||
QByteArray CPICUploader::GetCurDataChunk(bool &IsLastChunk)
|
||||
{
|
||||
QByteArray Chunk;
|
||||
QByteArray Payload;
|
||||
Chunk.clear();
|
||||
|
||||
unsigned int index = mFirmwareUploadCurFrame * mFirmwareUploadBufferSize;
|
||||
if((index + mFirmwareUploadBufferSize) >= mFirmwareData.size())
|
||||
{
|
||||
IsLastChunk = true;
|
||||
}
|
||||
|
||||
Payload = mFirmwareData.mid(index,mFirmwareUploadBufferSize);
|
||||
|
||||
Chunk.append(IntToByteArray(mFirmwareUploadCurFrame));
|
||||
Chunk.append(IntToByteArray(Payload.size()));
|
||||
Chunk.append(Payload);
|
||||
|
||||
return Chunk;
|
||||
}
|
||||
|
||||
|
||||
QByteArray CPICUploader::IntToByteArray(int data)
|
||||
{
|
||||
QByteArray Array;
|
||||
unsigned char nibble = (char)((data >> 24) &0x000000FF);
|
||||
Array.append(nibble);
|
||||
|
||||
nibble = (char)((data >> 16) &0x000000FF);
|
||||
Array.append(nibble);
|
||||
|
||||
nibble = (char)((data >> 8) &0x000000FF);
|
||||
Array.append(nibble);
|
||||
|
||||
nibble = (char)(data &0x000000FF);
|
||||
Array.append(nibble);
|
||||
|
||||
return Array;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,123 @@
|
||||
#include <QObject>
|
||||
#include "PICUploaderGui.h"
|
||||
#include "HexFile.h"
|
||||
#include <QTcpSocket>
|
||||
#include "BootloaderProtocol.h"
|
||||
|
||||
enum eBootloaderUploadSMEvents
|
||||
{
|
||||
BOOTLOADER_UPLOAD_SM_TICK_EVENT,
|
||||
BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,
|
||||
|
||||
BOOTLOADER_UPLOAD_SM_MAX_EVENT
|
||||
};
|
||||
|
||||
enum eBootloaderSMCmdEvents
|
||||
{
|
||||
BOOTLOADER_UPLOAD_ERASE_FLASH_GUI_CMD,
|
||||
BOOTLOADER_UPLOAD_START_UPLOAD_GUI_CMD,
|
||||
BOOTLOADER_UPLOAD_START_FULL_UPDATE_GUI_CMD,
|
||||
BOOTLOADER_UPLOAD_ABORT_GUI_CMD,
|
||||
BOOTLOADER_UPLOAD_BOOTLOADER_CONNECTED_CMD,
|
||||
BOOTLOADER_UPLOAD_BOOTLOADER_DISCONNECTED_CMD,
|
||||
|
||||
BOOTLOADER_UPLOAD_HEARTBEAT_HOST_CMD,
|
||||
BOOTLOADER_UPLOAD_ERASE_BOOTLOADER_FLASH_ACK_HOST_CMD,
|
||||
BOOTLOADER_UPLOAD_ERASE_BOOTLOADER_FLASH_RESULT_HOST_CMD,
|
||||
BOOTLOADER_UPLOAD_INIT_UPLOAD_HOST_CMD,
|
||||
BOOTLOADER_UPLOAD_GET_STATE_HOST_CMD,
|
||||
BOOTLOADER_UPLOAD_READY_FOR_DATA_HOST_CMD,
|
||||
BOOTLOADER_UPLOAD_SEND_DATA_CHUNK_HOST_CMD,
|
||||
BOOTLOADER_UPLOAD_UPLOAD_FINISHED_HOST_CMD,
|
||||
BOOTLOADER_UPLOAD_EXECUTE_UPGRADE_HOST_CMD,
|
||||
BOOTLOADER_UPLOAD_ABORT_OPERATION_HOST_CMD,
|
||||
|
||||
BOOTLOADER_UPLOAD_MAX_CMD
|
||||
};
|
||||
|
||||
typedef enum eBootloaderInterfaceSMStates
|
||||
{
|
||||
BOOTLOADER_INTERFACE_SM_STANDBY_STATE,
|
||||
BOOTLOADER_INTERFACE_SM_BOOTLDR_CONNECTED_STATE,
|
||||
BOOTLOADER_INTERFACE_SM_ERASE_FLASH_STATE,
|
||||
BOOTLOADER_INTERFACE_SM_WAIT_READY_FOR_DATA_FROM_HOST_STATE,
|
||||
BOOTLOADER_INTERFACE_SM_INIT_UPLOAD_STATE,
|
||||
BOOTLOADER_INTERFACE_SM_SEND_DATA_STATE,
|
||||
BOOTLOADER_INTERFACE_SM_DATA_FINISHED_STATE,
|
||||
|
||||
BOOTLOADER_UPLOAD_MAX_STATE
|
||||
}BootloaderInterfaceSMStates;
|
||||
|
||||
typedef enum eBootloaderFirmwareUploadSMStates
|
||||
{
|
||||
BOOTLOADER_FIRM_UPLD_STANDBY_STATE,
|
||||
// BOOTLOADER_FIRM_UPLD_WAIT_FOR_HOST_READY_STATE,
|
||||
BOOTLOADER_FIRM_UPLD_SEND_CHUNK_STATE,
|
||||
BOOTLOADER_FIRM_UPLD_FINISHED_STATE,
|
||||
|
||||
BOOTLOADER_FIRM_UPLD_MAX_STATE
|
||||
}BootloaderFirmwareUpldState;
|
||||
|
||||
enum eBootloaderFirmwareUploadEvents
|
||||
{
|
||||
BOOTLOADER_FIRM_UPLD_TICK_EVENT,
|
||||
BOOTLOADER_FIRM_UPLD_CMD_EVENT,
|
||||
|
||||
BOOTLOADER_FIRM_UPLD_MAX_EVENT
|
||||
};
|
||||
|
||||
enum eBootloaderFirmwareUploadSMCmd
|
||||
{
|
||||
BOOTLOADER_FIRM_UPLD_INIT_UPLOAD_CMD,
|
||||
BOOTLOADER_FIRM_UPLD_CHUNK_RX_RESPONSE_CMD,
|
||||
BOOTLOADER_FIRM_UPLD_ABORT_UPLOAD_CMD,
|
||||
|
||||
BOOTLOADER_FIRM_UPLD_MAX_CMD
|
||||
};
|
||||
|
||||
enum eBootloaderProtocolDataTransferError
|
||||
{
|
||||
BOOTLOADER_CHUNK_TRANSFER_SUCCESS = 1,
|
||||
BOOTLOADER_CHUNK_TRANSFER_ERROR_RESEND = 2,
|
||||
BOOTLOADER_CHUNK_TRANSFER_ERROR_FLASH_FAILURE = 3,
|
||||
BOOTLOADER_CHUNK_TRANSFER_ERROR_INVALID_CHUNK_INDEX = 4,
|
||||
BOOTLOADER_CHUNK_TRANSFER_ERROR_FLASH_ERROR = 5,
|
||||
|
||||
BOOTLOADER_CHUNK_TRANSFER_MAX_ERROR
|
||||
};
|
||||
|
||||
enum eBootloaderProtocolInitUploadError
|
||||
{
|
||||
BOOTLOADER_INIT_UPLOAD_FAILED = 0,
|
||||
BOOTLOADER_INIT_UPLOAD_SUCCESS = 1,
|
||||
BOOTLOADER_INIT_UPLOAD_ERROR_FLASH_NOT_ERASED = 2,
|
||||
|
||||
BOOTLOADER_INIT_UPLOAD_MAX_ERROR
|
||||
};
|
||||
|
||||
enum eBootloaderFirmwareUploadRes
|
||||
{
|
||||
|
||||
BOOTLOADER_FIRM_UPLD_STANDBY_RES,
|
||||
BOOTLOADER_FIRM_UPLD_SENDING_RES,
|
||||
BOOTLOADER_FIRM_UPLD_FINISHED_RES,
|
||||
BOOTLOADER_FIRM_UPLD_ERROR_RES,
|
||||
BOOTLOADER_FIRM_UPLD_TIMEOUT_RES,
|
||||
BOOTLOADER_FIRM_UPLD_ABORT_RES,
|
||||
BOOTLOADER_FIRM_UPLD_OK_RES,
|
||||
|
||||
BOOTLOADER_FIRM_UPLD_MAX_RES
|
||||
};
|
||||
|
||||
//Used for both ACK and erase operation result
|
||||
enum eBootloaderFlashEraseResult
|
||||
{
|
||||
BOOTLOADER_FLASH_ERASE_ERROR = 0,
|
||||
BOOTLOADER_FLASH_ERASE_OK = 1,
|
||||
|
||||
BOOTLOADER_FLASH_ERASE_MAX_RESULT
|
||||
};
|
||||
|
||||
|
||||
class CPICUploader : public QObject
|
||||
{
|
||||
@@ -18,10 +135,42 @@ public:
|
||||
|
||||
CHexFile mHexFile;
|
||||
|
||||
QTcpSocket mBootloaderSocket;
|
||||
CBootloaderProtocol mBootloaderProtocol;
|
||||
|
||||
int ConnectToBootloader(QString IP);
|
||||
int DisconnectFromBootloader();
|
||||
int SendSingleCmdRequest(int CmdID);
|
||||
int SendCmdRequest(int CmdID, QByteArray Data);
|
||||
int GuiEvent(int EventID, void* Data=0);
|
||||
int ShowHexFileInfoRequest();
|
||||
|
||||
int BootloaderRxCmd(int CmdID, QByteArray Data);
|
||||
|
||||
int BootloaderFirmwareUploadStateMachine(int Event, int Cmd, int CmdResult = 1, int CmdParam = 0xBAADCAFE);
|
||||
int BootloaderInterfaceStateMachine(int Event, int Cmd, int CmdParam = 0, void *Data = 0);
|
||||
|
||||
|
||||
private:
|
||||
BootloaderInterfaceSMStates mBootloaderInterfaceSMState;
|
||||
int ResetBooloaderInterfaceStateMachine();
|
||||
BootloaderFirmwareUpldState mBootloaderFirmwareUpldState;
|
||||
int ResetFirmwareUploadStateMachine();
|
||||
unsigned int mFirmwareUploadBufferSize;
|
||||
unsigned int mFirmwareUploadCurFrame;
|
||||
QByteArray mFirmwareData;
|
||||
QByteArray GetCurDataChunk(bool &IsLastChunk);
|
||||
QByteArray IntToByteArray(int);
|
||||
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void BootloaderSocketConnected();
|
||||
void BootloaderSocketDisconnected();
|
||||
void BootloaderDataAvailable();
|
||||
void BootloaderSocketError(QAbstractSocket::SocketError);
|
||||
};
|
||||
|
||||
#endif // PICUPLOADER_H
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "ui_PICUploaderGui.h"
|
||||
#include <QFileDialog>
|
||||
#include "PICUploader.h"
|
||||
#include "ProtocolDefs.h"
|
||||
|
||||
CPICUploaderGui::CPICUploaderGui(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
@@ -10,6 +11,10 @@ CPICUploaderGui::CPICUploaderGui(QWidget *parent) :
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->mHexFileSelectBtn,SIGNAL(clicked(bool)),this,SLOT(OpenHexFileBtnClicked(bool)));
|
||||
connect(ui->mConnectBtn,SIGNAL(clicked(bool)),this,SLOT(ConnectBtnClicked(bool)));
|
||||
connect(ui->mSendCmdBtn,SIGNAL(clicked(bool)),this,SLOT(SendSingleCmdCliked(bool)));
|
||||
connect(ui->mClearLogginWndwBtn,SIGNAL(clicked(bool)),SLOT(ClearLogScreen(bool)));
|
||||
connect(ui->mShowHexFileInfoBtn,SIGNAL(clicked(bool)),this,SLOT(ShowHexFileInfoClicked(bool)));
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +26,7 @@ CPICUploaderGui::~CPICUploaderGui()
|
||||
void CPICUploaderGui::OpenHexFileBtnClicked(bool checked)
|
||||
{
|
||||
QString FileName = QFileDialog::getOpenFileName(0,"Select Firmware Hex File",QString(),"Hex files (*.hex)");
|
||||
if(mProgramHandle->OpenHexFileRequest(FileName) != 0)
|
||||
if(mProgramHandle->OpenHexFileRequest(FileName) != 1)
|
||||
{
|
||||
ui->mOpenedHexFilePathLbl->setText(FileName);
|
||||
}
|
||||
@@ -32,3 +37,128 @@ void CPICUploaderGui::SetHexFileStats(QString Stats)
|
||||
{
|
||||
ui->mHexFileStatsLbl->setText(Stats);
|
||||
}
|
||||
|
||||
void CPICUploaderGui::ConnectBtnClicked(bool)
|
||||
{
|
||||
if(ui->mConnectBtn->text() == "Connect")
|
||||
{
|
||||
QString IP = ui->mIPAddressEdit->text();
|
||||
if(IP.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// ui->mConnectBtn->setText("Disconnect");
|
||||
// ui->mConnectBtn->setEnabled(false);
|
||||
mProgramHandle->ConnectToBootloader(IP);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ui->mConnectBtn->setText("Connect");
|
||||
mProgramHandle->DisconnectFromBootloader();
|
||||
}
|
||||
}
|
||||
|
||||
void CPICUploaderGui::UploaderSocketConnected()
|
||||
{
|
||||
ui->mConnectBtn->setEnabled(true);
|
||||
ui->mConnectBtn->setText("Disconnect");
|
||||
}
|
||||
|
||||
void CPICUploaderGui::UploaderSocketDisconnected()
|
||||
{
|
||||
ui->mConnectBtn->setEnabled(true);
|
||||
ui->mConnectBtn->setText("Connect");
|
||||
}
|
||||
|
||||
void CPICUploaderGui::SendSingleCmdCliked(bool)
|
||||
{
|
||||
QString CmdSelection = ui->mCmdSelectCombo->currentText();
|
||||
|
||||
if(CmdSelection == "Heartbeat")
|
||||
{
|
||||
// mProgramHandle->SendSingleCmdRequest(BOOTLOADER_HEARTBEAT_REQUEST);
|
||||
mProgramHandle->GuiEvent(UPLOADER_GUI_HEARTBEAT_BTN_CLICK_EVENT);
|
||||
}
|
||||
else if(CmdSelection == "Flash Erase")
|
||||
{
|
||||
//mProgramHandle->SendSingleCmdRequest(BOOTLOADER_ERASE_BOOTLOADER_FLASH_REQUEST);
|
||||
mProgramHandle->GuiEvent(UPLOADER_GUI_FLASH_ERASE_BTN_CLICK_EVENT);
|
||||
}
|
||||
else if(CmdSelection == "Init Upload")
|
||||
{
|
||||
// mProgramHandle->SendSingleCmdRequest(BOOTLOADER_INIT_UPLOAD_REQUEST);
|
||||
mProgramHandle->GuiEvent(UPLOADER_GUI_INIT_UPLOAD_BTN_CLICK_EVENT);
|
||||
}
|
||||
else if(CmdSelection == "Get State")
|
||||
{
|
||||
// mProgramHandle->SendSingleCmdRequest(BOOTLOADER_GET_STATE_REQUEST);
|
||||
mProgramHandle->GuiEvent(UPLOADER_GUI_GET_STATE_BTN_CLICK_EVENT);
|
||||
}
|
||||
else if(CmdSelection == "Send Data Chunk")
|
||||
{
|
||||
// mProgramHandle->SendSingleCmdRequest(BOOTLOADER_SEND_DATA_CHUNK_REQUEST);
|
||||
mProgramHandle->GuiEvent(UPLOADER_GUI_SEND_DATA_CHUNK_BTN_CLICK_EVENT);
|
||||
}
|
||||
else if(CmdSelection == "Upload Finished")
|
||||
{
|
||||
// mProgramHandle->SendSingleCmdRequest(BOOTLOADER_UPLOAD_FINISHED_REQUEST);
|
||||
mProgramHandle->GuiEvent(UPLOADER_GUI_UPLOAD_FINISHED_BTN_CLICK_EVENT);
|
||||
}
|
||||
else if(CmdSelection == "Execute Upgrade")
|
||||
{
|
||||
// mProgramHandle->SendSingleCmdRequest(BOOTLOADER_EXECUTE_UPGRAGE_REQUEST);
|
||||
mProgramHandle->GuiEvent(UPLOADER_GUI_EXECUTE_UPGRADE_BTN_CLICK_EVENT);
|
||||
}
|
||||
else if(CmdSelection == "Abort")
|
||||
{
|
||||
// mProgramHandle->SendSingleCmdRequest(BOOTLOADER_ABORT_OPERATION_REQUEST);
|
||||
mProgramHandle->GuiEvent(UPLOADER_GUI_ABORT_BTN_CLICK_EVENT);
|
||||
}
|
||||
else if(CmdSelection == "Check Flash")
|
||||
{
|
||||
mProgramHandle->GuiEvent(UPLOADER_GUI_CHECK_FLASH_CLICK_EVENT);
|
||||
}
|
||||
else if(CmdSelection == "Get Stored Firmware Info")
|
||||
{
|
||||
mProgramHandle->GuiEvent(UPLOADER_GUI_GET_STORED_FIRMWARE_INFO_CLICK_EVENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("Unknown selection???!!!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CPICUploaderGui::AddTextToLogScreen(QString Text)
|
||||
{
|
||||
Text.append("\n");
|
||||
mLogScreenText.prepend(Text);
|
||||
ui->mLoggingWindowTextEdit->setPlainText(mLogScreenText);
|
||||
}
|
||||
|
||||
void CPICUploaderGui::ClearLogScreen(bool dummy)
|
||||
{
|
||||
mLogScreenText.clear();
|
||||
ui->mLoggingWindowTextEdit->setPlainText(mLogScreenText);
|
||||
}
|
||||
|
||||
void CPICUploaderGui::ShowHexFileInfoClicked(bool)
|
||||
{
|
||||
mProgramHandle->ShowHexFileInfoRequest();
|
||||
}
|
||||
|
||||
void CPICUploaderGui::SetUploadProgressSettings(int max)
|
||||
{
|
||||
ui->mUploadProgressBar->setRange(0,max);
|
||||
}
|
||||
|
||||
void CPICUploaderGui::TickProgressBar()
|
||||
{
|
||||
ui->mUploadProgressBar->setValue(ui->mUploadProgressBar->value()+1);
|
||||
}
|
||||
|
||||
void CPICUploaderGui::ResetProgressBar()
|
||||
{
|
||||
ui->mUploadProgressBar->reset();
|
||||
}
|
||||
|
||||
@@ -13,19 +13,50 @@ class CPICUploaderGui : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum eUploaderGuiEvents
|
||||
{
|
||||
UPLOADER_GUI_HEARTBEAT_BTN_CLICK_EVENT,
|
||||
UPLOADER_GUI_FLASH_ERASE_BTN_CLICK_EVENT,
|
||||
UPLOADER_GUI_INIT_UPLOAD_BTN_CLICK_EVENT,
|
||||
UPLOADER_GUI_GET_STATE_BTN_CLICK_EVENT,
|
||||
UPLOADER_GUI_SEND_DATA_CHUNK_BTN_CLICK_EVENT,
|
||||
UPLOADER_GUI_UPLOAD_FINISHED_BTN_CLICK_EVENT,
|
||||
UPLOADER_GUI_EXECUTE_UPGRADE_BTN_CLICK_EVENT,
|
||||
UPLOADER_GUI_ABORT_BTN_CLICK_EVENT,
|
||||
UPLOADER_GUI_AUTOMATIC_UPDATE_START_BTN_CLICK_EVENT,
|
||||
UPLOADER_GUI_CHECK_FLASH_CLICK_EVENT,
|
||||
UPLOADER_GUI_GET_STORED_FIRMWARE_INFO_CLICK_EVENT,
|
||||
|
||||
UPLOADER_GUI_MAX_EVENT
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
explicit CPICUploaderGui(QWidget *parent = nullptr);
|
||||
~CPICUploaderGui();
|
||||
|
||||
void SetHexFileStats(QString Stats);
|
||||
void UploaderSocketConnected();
|
||||
void UploaderSocketDisconnected();
|
||||
void AddTextToLogScreen(QString Text);
|
||||
void SetUploadProgressSettings(int max);
|
||||
void TickProgressBar();
|
||||
void ResetProgressBar();
|
||||
|
||||
|
||||
CPICUploader *mProgramHandle;
|
||||
|
||||
private:
|
||||
Ui::CPICUploaderGui *ui;
|
||||
QString mLogScreenText;
|
||||
|
||||
public slots:
|
||||
void OpenHexFileBtnClicked(bool);
|
||||
void ConnectBtnClicked(bool);
|
||||
void SendSingleCmdCliked(bool);
|
||||
void ClearLogScreen(bool);
|
||||
void ShowHexFileInfoClicked(bool);
|
||||
};
|
||||
|
||||
#endif // PICUPLOADERGUI_H
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<string>Open Hex File</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<widget class="QLineEdit" name="mIPAddressEdit">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>690</x>
|
||||
@@ -55,6 +55,9 @@
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>192.168.50.126</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="mOpenedHexFilePathLbl">
|
||||
<property name="geometry">
|
||||
@@ -78,10 +81,243 @@
|
||||
<height>131</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="mConnectBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>890</x>
|
||||
<y>120</y>
|
||||
<width>75</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="mSendCmdBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>890</x>
|
||||
<y>170</y>
|
||||
<width>75</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Send Cmd</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QComboBox" name="mCmdSelectCombo">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>710</x>
|
||||
<y>170</y>
|
||||
<width>151</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Heartbeat</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Get Stored Firmware Info</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Flash Erase</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Init Upload</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Get State</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Send Data Chunk</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Upload Finished</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Execute Upgrade</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Check Flash</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Abort</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
<widget class="QPlainTextEdit" name="mLoggingWindowTextEdit">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>310</y>
|
||||
<width>651</width>
|
||||
<height>341</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="mClearLogginWndwBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>660</y>
|
||||
<width>75</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="mShowHexFileInfoBtn">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>170</x>
|
||||
<y>110</y>
|
||||
<width>75</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Info</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="mFilterParamsLbl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>680</x>
|
||||
<y>320</y>
|
||||
<width>231</width>
|
||||
<height>81</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="mFilterStartAddressTxtEdit">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>760</x>
|
||||
<y>330</y>
|
||||
<width>113</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0x1D004000</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="mFilterEndAddressTxtEdit">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>760</x>
|
||||
<y>370</y>
|
||||
<width>113</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0x1D07FFFF</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>690</x>
|
||||
<y>330</y>
|
||||
<width>71</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>690</x>
|
||||
<y>370</y>
|
||||
<width>71</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>End Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>680</x>
|
||||
<y>300</y>
|
||||
<width>71</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Code area</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QProgressBar" name="mUploadProgressBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>680</x>
|
||||
<y>420</y>
|
||||
<width>231</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
Reference in New Issue
Block a user