409 lines
13 KiB
C++
409 lines
13 KiB
C++
#include "qgftfptargetsim.h"
|
|
|
|
#include <QUdpSocket>
|
|
#include <QNetworkDatagram>
|
|
#include <QTimerEvent>
|
|
#include <QTimer>
|
|
#include <QFile>
|
|
|
|
#include <QDebug>
|
|
|
|
#include "bsk_tftpd.h"
|
|
#include "bsk_tftp_pfs.h"
|
|
|
|
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
|
|
|
static bsk_download_site_t sites[]=
|
|
{
|
|
{"ZynQ", "0x94", 0, 0, 6,
|
|
{
|
|
{"BL", bsk_download_partition_t::part_null, 64*1024},
|
|
{"MM", bsk_download_partition_t::part_null, 128*1024},
|
|
{"APP0", bsk_download_partition_t::part_null, 1*1024*1024},
|
|
{"APP1", bsk_download_partition_t::part_null, 1*1024*1024},
|
|
{"PL0", bsk_download_partition_t::part_null, 1*1024*1024},
|
|
{"PL1", bsk_download_partition_t::part_null, 1*1024*1024}
|
|
}
|
|
},
|
|
{"ZynQ", "0x95", 0, 0, 7,
|
|
{
|
|
{"BL", bsk_download_partition_t::part_null, 64*1024},
|
|
{"MM", bsk_download_partition_t::part_null, 128*1024},
|
|
{"OPER", bsk_download_partition_t::part_null, 1*1024*1024},
|
|
{"PL0", bsk_download_partition_t::part_null, 1*1024*1024},
|
|
{"PL1", bsk_download_partition_t::part_null, 1*1024*1024},
|
|
{"FPGA0", bsk_download_partition_t::part_null, 0},
|
|
{"FPGA1", bsk_download_partition_t::part_null, 0}
|
|
}
|
|
},
|
|
|
|
{"DSP", "0x54", 0, 0, 4,
|
|
{
|
|
{"BL", bsk_download_partition_t::part_fsbl|bsk_download_partition_t::part_hidden, 64*1024},
|
|
{"MM", bsk_download_partition_t::part_recovery|bsk_download_partition_t::part_hidden, 128*1024},
|
|
{"OPER", bsk_download_partition_t::part_operative|bsk_download_partition_t::part_default, 1*1024*1024},
|
|
{"APP2", 0, 1*1024*1024}
|
|
}
|
|
},
|
|
{"DSP", "0x54", 0, 0, 4,
|
|
{
|
|
{"BL", bsk_download_partition_t::part_fsbl|bsk_download_partition_t::part_hidden, 64*1024},
|
|
{"MM", bsk_download_partition_t::part_recovery|bsk_download_partition_t::part_hidden, 128*1024},
|
|
{"OPER", bsk_download_partition_t::part_operative|bsk_download_partition_t::part_default, 1*1024*1024},
|
|
{"APP2", 0, 1*1024*1024}
|
|
}
|
|
},
|
|
{"DSP", "0x54", 0, 0, 4,
|
|
{
|
|
{"BL", bsk_download_partition_t::part_fsbl|bsk_download_partition_t::part_hidden, 64*1024},
|
|
{"MM", bsk_download_partition_t::part_recovery|bsk_download_partition_t::part_hidden, 128*1024},
|
|
{"OPER", bsk_download_partition_t::part_operative|bsk_download_partition_t::part_default, 1*1024*1024},
|
|
{"APP2", 0, 1*1024*1024}
|
|
}
|
|
},
|
|
{"DSP", "0x54", 0, 0, 4,
|
|
{
|
|
{"BL", bsk_download_partition_t::part_fsbl|bsk_download_partition_t::part_hidden, 64*1024},
|
|
{"MM", bsk_download_partition_t::part_recovery|bsk_download_partition_t::part_hidden, 128*1024},
|
|
{"OPER", bsk_download_partition_t::part_operative|bsk_download_partition_t::part_default, 1*1024*1024},
|
|
{"APP2", 0, 1*1024*1024}
|
|
}
|
|
}
|
|
};
|
|
|
|
class QgTftpTargetSim::Implementation
|
|
{
|
|
public:
|
|
QString name;
|
|
int site_id;
|
|
|
|
QObject* parent;
|
|
QUdpSocket tftpServer;
|
|
|
|
//static Implementation* gInstance;
|
|
QHostAddress clientAddress;
|
|
int clientPort;
|
|
//int timerId;
|
|
QTimer storeTimer;
|
|
QFile storeFile;
|
|
QByteArray storeBuffer;
|
|
bsk_download_partition_t* currentParitition;
|
|
|
|
int store_time;
|
|
int progr_time;
|
|
|
|
bsk_tftpd_context_id_t id;
|
|
const bsk_tftpd_context_info_t* tftpd_cx;
|
|
|
|
int state;
|
|
|
|
Implementation(const QString& n, int sid, QObject* p):
|
|
name(n),
|
|
site_id(sid),
|
|
parent(p),
|
|
tftpServer(p)
|
|
{
|
|
//gInstance=this;
|
|
store_time=2*1000;
|
|
progr_time=2*1000;
|
|
storeTimer.setSingleShot(true);
|
|
storeBuffer.reserve(1024*1024);
|
|
currentParitition=0;
|
|
state=0;
|
|
}
|
|
|
|
void processPendingDatagram()
|
|
{
|
|
while(tftpServer.hasPendingDatagrams())
|
|
{
|
|
QNetworkDatagram d=tftpServer.receiveDatagram();
|
|
//qDebug()<<"RCV:"<<d.data().size();
|
|
auto cAddress=d.senderAddress();
|
|
auto cPort=d.senderPort();
|
|
#if 0
|
|
if (!tftpServer.isOpen())
|
|
{
|
|
tftpServer.connectToHost(d.senderAddress(), d.senderPort());
|
|
qDebug()<<"Connect to"<<d.senderAddress()<<d.senderPort();
|
|
}
|
|
else if ((tftpServer.peerPort()!=d.senderPort()) || (tftpServer.peerAddress()!=d.senderAddress()))
|
|
{
|
|
tftpServer.connectToHost(d.senderAddress(), d.senderPort());
|
|
qDebug()<<"Connect to"<<d.senderAddress()<<d.senderPort();
|
|
}
|
|
#endif
|
|
int r=bsk_tftpd_process_packet(id, cAddress.toIPv4Address(), cPort,
|
|
d.data().constData(), d.data().size());
|
|
if (r==0)
|
|
{
|
|
clientAddress=cAddress;
|
|
clientPort=cPort;
|
|
}
|
|
else if (r!=-100)
|
|
{
|
|
qDebug()<<"Disconnect";
|
|
//tftpServer.disconnectFromHost();
|
|
}
|
|
}
|
|
}
|
|
|
|
static int bsk_tftpd_log_delegate(bsk_tftpd_context_id_t id, const char* const msg, ...)
|
|
{
|
|
const bsk_tftpd_context_info_t* cx=bsk_tftpd_context_info(id);
|
|
va_list args;
|
|
va_start(args, msg);
|
|
qDebug()<<id<<cx->name<<cx->port<<QString::vasprintf(msg, args);
|
|
va_end(args);
|
|
return 0;
|
|
}
|
|
|
|
char* progr_msg(const char* msg, int n=0)
|
|
{
|
|
static char buffer[512];
|
|
if (n==0)
|
|
{
|
|
int i=storeTimer.interval();
|
|
int r=storeTimer.remainingTime();
|
|
n=(float(i-r)/float(i))*100;
|
|
if (n>100)
|
|
n=100;
|
|
if (n<0)
|
|
n=-1;
|
|
}
|
|
sprintf(buffer, "%d %s", n, msg);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
static bsk_tftpd_receive_status_t bsk_tftpd_receive_delegate(bsk_tftpd_context_id_t id, bsk_tftpd_receive_delegate_operation_t op, const void* const data, unsigned int block, unsigned int offset, unsigned int size_bytes)
|
|
{
|
|
const bsk_tftpd_context_info_t* cx=bsk_tftpd_context_info(id);
|
|
Implementation* gInstance=reinterpret_cast<Implementation*>(cx->cookie);
|
|
|
|
bsk_tftpd_receive_status_t sts={bsk_tftpd_ok, 0};
|
|
if (op==bsk_tftpd_open_read_not_supported)
|
|
{
|
|
if (strcmp(bsk_tftpd_mfs_status_query, (char*)data)==0)
|
|
{
|
|
if (gInstance->state==0)
|
|
{
|
|
sts.sts=bsk_tftpd_err_not_found;
|
|
sts.ack_msg="ready";
|
|
}
|
|
else if (gInstance->state==2)
|
|
{
|
|
sts.sts=bsk_tftpd_err_bad_id;
|
|
sts.ack_msg=gInstance->progr_msg("Erasing");
|
|
}
|
|
else if (gInstance->state==3)
|
|
{
|
|
sts.sts=bsk_tftpd_err_bad_id;
|
|
sts.ack_msg=gInstance->progr_msg("Storing");
|
|
}
|
|
else
|
|
{
|
|
sts.sts=bsk_tftpd_err_bad_id;
|
|
sts.ack_msg="busy";
|
|
}
|
|
}
|
|
else if (strcmp(bsk_tftpd_mfs_list_query, (char*)data)==0)
|
|
{
|
|
sts.sts=bsk_tftpd_err_file_exists;
|
|
sts.ack_msg=bsk_tftpd_mfs_get_list(id);
|
|
}
|
|
else
|
|
sts.sts=bsk_tftpd_err_not_found;
|
|
return sts;
|
|
}
|
|
|
|
if ((op==bsk_tftpd_open_file) && (gInstance->state>0))
|
|
{
|
|
static QString reply_msg;
|
|
static char cmsg[512];
|
|
sts.sts=bsk_tftpd_err_not_found;
|
|
int remain=gInstance->storeTimer.remainingTime();
|
|
float store_completition=100*(5000.0f/(5000.0f-float(remain)));
|
|
reply_msg=QString::asprintf("%u%% storing", int(store_completition));
|
|
strncpy(cmsg, reply_msg.toLatin1().constData(), sizeof cmsg);
|
|
sts.ack_msg=0; //cmsg;
|
|
qDebug()<<sts.sts<<sts.ack_msg;
|
|
}
|
|
else if (op==bsk_tftpd_open_file)
|
|
{
|
|
const char* fname;
|
|
gInstance->currentParitition=0;
|
|
bsk_download_partition_t* p=bsk_tftp_mfs_decode_filename(gInstance->site_id, (char*)data, &fname);
|
|
if (p==bsk_tftp_mfs_invalid_partition)
|
|
{
|
|
sts.sts=bsk_tftpd_err_not_found;
|
|
sts.ack_msg=0;
|
|
return sts;
|
|
}
|
|
gInstance->state=1;
|
|
if (p)
|
|
{
|
|
if (gInstance->storeFile.isOpen())
|
|
{
|
|
qDebug()<<"WARNING:store file is open!!!";
|
|
gInstance->storeFile.close();
|
|
}
|
|
//gInstance->storeFile.setFileName(QString("_%1_%2.dat").arg(gInstance->site_id).arg(p->name));
|
|
//gInstance->storeFile.open(QIODevice::WriteOnly);
|
|
gInstance->storeBuffer.clear();
|
|
gInstance->storeBuffer.reserve(1024*1024);
|
|
gInstance->currentParitition=p;
|
|
}
|
|
|
|
}
|
|
else if (op==bsk_tftpd_data)
|
|
{
|
|
//if (gInstance->storeFile.isOpen())
|
|
//{
|
|
// gInstance->storeFile.write((char*)data, size_bytes);
|
|
//}
|
|
gInstance->storeBuffer.append((char*)data, size_bytes);
|
|
}
|
|
else if (op==bsk_tftpd_end)
|
|
{
|
|
//if (gInstance->storeFile.isOpen())
|
|
//{
|
|
// gInstance->storeFile.write((char*)data, size_bytes);
|
|
// gInstance->storeFile.flush(); //close();
|
|
//}
|
|
if (gInstance->currentParitition)
|
|
{
|
|
if (gInstance->storeBuffer.size()>gInstance->currentParitition->max_size)
|
|
{
|
|
sts.sts=bsk_tftpd_err_no_space;
|
|
sts.ack_msg="file too big";
|
|
}
|
|
else
|
|
{
|
|
if (size_bytes)
|
|
gInstance->storeBuffer.append((char*)data, size_bytes);
|
|
|
|
sts.sts=bsk_tftpd_dont_ack;
|
|
gInstance->storeTimer.start(gInstance->store_time);
|
|
gInstance->storeFile.setFileName(QString("_%1_%2.dat").arg(gInstance->site_id).arg(gInstance->currentParitition->name));
|
|
bool ok=gInstance->storeFile.open(QIODevice::WriteOnly);
|
|
if (ok)
|
|
{
|
|
gInstance->storeFile.write(gInstance->storeBuffer);
|
|
gInstance->storeFile.close();
|
|
gInstance->state=2;
|
|
}
|
|
else
|
|
{
|
|
sts.sts=bsk_tftpd_err_access;
|
|
sts.ack_msg="error storing";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gInstance->state=0;
|
|
}
|
|
}
|
|
|
|
return sts;
|
|
}
|
|
|
|
static int bsk_tftpd_send_delegate(bsk_tftpd_context_id_t id, unsigned int adr, unsigned int port, const void* const data, unsigned int size)
|
|
{
|
|
const bsk_tftpd_context_info_t* cx=bsk_tftpd_context_info(id);
|
|
Implementation* gInstance=reinterpret_cast<Implementation*>(cx->cookie);
|
|
|
|
QHostAddress ha(gInstance->clientAddress);
|
|
int hp=gInstance->clientPort;
|
|
if (adr)
|
|
ha=QHostAddress(adr);
|
|
if (port)
|
|
hp=port;
|
|
|
|
qDebug()<<"TFTP: send"<<QString("%1").arg(ha.toIPv4Address(), 0, 16)<<hp<<size;
|
|
gInstance->tftpServer.writeDatagram((char*)data, size, ha, hp); //gInstance->clientAddress, gInstance->clientPort);
|
|
return 0;
|
|
}
|
|
|
|
};
|
|
|
|
//QgFtfpTargetSim::Implementation* QgFtfpTargetSim::Implementation::gInstance;
|
|
|
|
QgTftpTargetSim::QgTftpTargetSim(const QString &name, int sid, int port):
|
|
p_(*new Implementation(name, sid, this))
|
|
{
|
|
bsk_tftpd_mfs_set_site(&sites[0], 3);
|
|
|
|
p_.tftpServer.bind(QHostAddress::LocalHost, port);
|
|
|
|
connect(&p_.tftpServer, &QUdpSocket::readyRead, this, pendingDatagram);
|
|
|
|
char* kn=strdup(name.toLatin1().constData());
|
|
|
|
p_.id=bsk_tftpd_context_initialize(-1, kn, port, &p_);
|
|
p_.tftpd_cx=bsk_tftpd_context_info(p_.id);
|
|
|
|
bsk_tftpd_set_log_delegate(p_.id, Implementation::bsk_tftpd_log_delegate);
|
|
bsk_tftpd_set_receive_delegate(p_.id, Implementation::bsk_tftpd_receive_delegate);
|
|
bsk_tftpd_set_send_delegate(p_.id, Implementation::bsk_tftpd_send_delegate);
|
|
|
|
connect(&p_.storeTimer, &QTimer::timeout, this, &timerExpired);
|
|
}
|
|
|
|
QgTftpTargetSim::~QgTftpTargetSim()
|
|
{
|
|
delete &p_;
|
|
}
|
|
|
|
void QgTftpTargetSim::pendingDatagram()
|
|
{
|
|
p_.processPendingDatagram();
|
|
}
|
|
|
|
void QgTftpTargetSim::setEraseTime(int t)
|
|
{
|
|
p_.store_time=t*1000;
|
|
}
|
|
|
|
void QgTftpTargetSim::setProgTime(int t)
|
|
{
|
|
p_.progr_time=t*1000;
|
|
}
|
|
|
|
void QgTftpTargetSim::timerExpired()
|
|
{
|
|
if (p_.state==2)
|
|
{
|
|
p_.state=3;
|
|
p_.storeTimer.start(p_.progr_time);
|
|
}
|
|
else if (p_.state==3)
|
|
{
|
|
p_.storeTimer.stop();
|
|
bsk_tftpd_send_ack(p_.id, bsk_tftpd_ok, 0);
|
|
if (p_.storeFile.isOpen())
|
|
{
|
|
qDebug()<<"File stored:"<<p_.storeFile.fileName();
|
|
p_.storeFile.close();
|
|
}
|
|
else
|
|
{
|
|
qDebug()<<"File not stored:"<<p_.storeFile.fileName();
|
|
}
|
|
p_.state=0;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
void QgFtfpTargetSim::timerEvent(QTimerEvent *event)
|
|
{
|
|
if (event->timerId()==p_.timerId)
|
|
{
|
|
if (state==2)
|
|
|
|
p_.timerId=0;
|
|
bsk_tftpd_send_ack(p_.id, bsk_tftpd_ok, 0);
|
|
}
|
|
}
|
|
#endif
|