225 lines
6.8 KiB
C++
225 lines
6.8 KiB
C++
#include "stpclient.h"
|
|
|
|
stpClient::stpClient(QHostAddress address, int port, QObject *parent)
|
|
: QObject{parent},
|
|
_state(stpClient_ns::stpState::DISCONNECTED),
|
|
_pingState(stpClient_ns::pingState::IDLE),
|
|
_socket(new QUdpSocket()),
|
|
_address(address),
|
|
_port(port),
|
|
_pingTimer(new QTimer()),
|
|
_pingTimeoutCount(0),
|
|
_reconnectionTimer(new QTimer())
|
|
{
|
|
_reconnectionTimer->setInterval(STP_RECONNECTION_PERIOD);
|
|
|
|
QObject::connect(_reconnectionTimer, &QTimer::timeout, [=]{
|
|
connectToHost();
|
|
});
|
|
|
|
QObject::connect(_socket, &QUdpSocket::readyRead,
|
|
this, [=](){
|
|
|
|
#ifdef STP_MANY_PACKETS_DEBUG
|
|
int __count = 0;
|
|
#endif
|
|
|
|
while (_socket->hasPendingDatagrams()) {
|
|
#ifdef STP_MANY_PACKETS_DEBUG
|
|
__count++;
|
|
#endif
|
|
_processData(_socket->receiveDatagram());
|
|
}
|
|
|
|
#ifdef STP_MANY_PACKETS_DEBUG
|
|
if (__count > 44) qDebug() << "Received packets at once(!): " << __count;
|
|
#endif
|
|
});
|
|
|
|
_pingTimer->setTimerType(Qt::PreciseTimer);
|
|
_pingTimer->setInterval(STP_PING_INTERVAL_MS);
|
|
|
|
QObject::connect(_pingTimer, &QTimer::timeout, [=]{
|
|
if (_state == stpClient_ns::stpState::CONNECTED) {
|
|
_socket->writeDatagram(_pack(stpProtocol_ns::packetType::PING), _address, _port);
|
|
_pingState = stpClient_ns::pingState::PENDING;
|
|
QTimer::singleShot(STP_TIMEOUT_MS, [=]{
|
|
if (_pingState == stpClient_ns::pingState::PENDING) {
|
|
#ifdef STP_DEBUG
|
|
qDebug() << QTime::currentTime().toString() << "ping timeout";
|
|
#endif
|
|
|
|
_pingTimeoutCount++;
|
|
|
|
if (_pingTimeoutCount >= STP_TIMEOUT_COUNT) {
|
|
disconnectFromHost();
|
|
emit STP_disconnected();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
stpClient::~stpClient()
|
|
{
|
|
delete _pingTimer;
|
|
delete _reconnectionTimer;
|
|
delete _socket;
|
|
#ifdef STP_DEBUG
|
|
qDebug() << "stpClient desctructor";
|
|
#endif
|
|
}
|
|
|
|
void stpClient::connectToHost()
|
|
{
|
|
if ((_state == stpClient_ns::stpState::DISCONNECTED) ||
|
|
(_state == stpClient_ns::stpState::CONNECTING)) {
|
|
_socket->writeDatagram(_pack(stpProtocol_ns::packetType::SYNCReq), _address, _port);
|
|
_state = stpClient_ns::stpState::CONNECTING;
|
|
_reconnectionTimer->start();
|
|
}
|
|
}
|
|
|
|
void stpClient::disconnectFromHost()
|
|
{
|
|
if (_state != stpClient_ns::stpState::DISCONNECTED) {
|
|
_socket->writeDatagram(_pack(stpProtocol_ns::packetType::RESET), _address, _port);
|
|
_state = stpClient_ns::stpState::DISCONNECTED;
|
|
_pingState = stpClient_ns::pingState::IDLE;
|
|
_pingTimer->stop();
|
|
}
|
|
}
|
|
|
|
void stpClient::sendData(QByteArray *buff)
|
|
{
|
|
if (_state == stpClient_ns::stpState::CONNECTED) {
|
|
_socket->writeDatagram(_pack(stpProtocol_ns::packetType::DATA, buff), _address, _port);
|
|
}
|
|
}
|
|
|
|
QByteArray stpClient::_pack(stpProtocol_ns::packetType packetType, QByteArray *data)
|
|
{
|
|
QByteArray __result;
|
|
|
|
if ( (packetType == stpProtocol_ns::packetType::DATA)
|
|
&& (data != nullptr) ) {
|
|
// data packet
|
|
trans_ns::bytes2word __size;
|
|
__size.word = data->size();
|
|
|
|
__result.resize(CONST_HEADER_SIZE);
|
|
__result[0] = packetType;
|
|
__result[1] = __size.bytes.L;
|
|
__result[2] = __size.bytes.H;
|
|
__result.append(*data);
|
|
} else {
|
|
// system packets
|
|
__result.resize(CONST_HEADER_SIZE);
|
|
__result[0] = packetType;
|
|
__result[1] = 0;
|
|
__result[2] = 0;
|
|
}
|
|
|
|
return __result;
|
|
}
|
|
|
|
QByteArray stpClient::packIdRequest()
|
|
{
|
|
QByteArray __result;
|
|
|
|
__result.resize(CONST_HEADER_SIZE + 1);
|
|
__result[0] = stpProtocol_ns::packetType::DATA;
|
|
__result[1] = 0x01;
|
|
__result[2] = 0x00;
|
|
__result[3] = (uint8_t)stpProtocol_ns::stpCommand::REQ_ID;
|
|
return __result;
|
|
}
|
|
|
|
QByteArray stpClient::packIdSnRequest(uint16_t sn)
|
|
{
|
|
trans_ns::bytes2word __sn;
|
|
|
|
__sn.word = sn;
|
|
|
|
QByteArray __result;
|
|
|
|
__result.resize(CONST_HEADER_SIZE + 3);
|
|
__result[0] = stpProtocol_ns::packetType::DATA;
|
|
__result[1] = 0x03;
|
|
__result[2] = 0x00;
|
|
__result[3] = (uint8_t)stpProtocol_ns::stpCommand::REQ_ID_SN;
|
|
__result[4] = __sn.bytes.L;
|
|
__result[5] = __sn.bytes.H;
|
|
return __result;
|
|
}
|
|
|
|
void stpClient::_processData(QNetworkDatagram dg)
|
|
{
|
|
int __size = dg.data().size();
|
|
|
|
if (__size < CONST_HEADER_SIZE) return;
|
|
|
|
QByteArray __header = dg.data().first(CONST_HEADER_SIZE);
|
|
QByteArray __data = dg.data().last(__size - CONST_HEADER_SIZE);
|
|
|
|
trans_ns::bytes2word __declaredSize;
|
|
|
|
__declaredSize.bytes.L = __header[1];
|
|
__declaredSize.bytes.H = __header[2];
|
|
|
|
if (__data.size() != __declaredSize.word) {
|
|
#ifdef STP_DEBUG
|
|
qDebug() << dg.senderAddress().toString() << "badPacketSize (packetSize: " << __data.size() << "; declaredSize: " << __declaredSize.word << ")";
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
switch (__header[0]) {
|
|
case stpProtocol_ns::packetType::PING:
|
|
if (_state == stpClient_ns::stpState::CONNECTED) {
|
|
_socket->writeDatagram(_pack(stpProtocol_ns::packetType::PONG), _address, _port);
|
|
} else {
|
|
_socket->writeDatagram(_pack(stpProtocol_ns::packetType::RESET), _address, _port);
|
|
}
|
|
break;
|
|
|
|
case stpProtocol_ns::packetType::PONG:
|
|
if (_pingState == stpClient_ns::pingState::PENDING) {
|
|
_pingState = stpClient_ns::pingState::IDLE;
|
|
_pingTimeoutCount = 0;
|
|
}
|
|
break;
|
|
|
|
case stpProtocol_ns::packetType::DATA:
|
|
emit STP_newDataPacketReceived(__data);
|
|
break;
|
|
|
|
case stpProtocol_ns::packetType::RESET:
|
|
#ifdef STP_DEBUG
|
|
qDebug() << "stp conection reset from: " << dg.senderAddress().toString();
|
|
#endif
|
|
_state = stpClient_ns::stpState::DISCONNECTED;
|
|
_pingState = stpClient_ns::pingState::IDLE;
|
|
_pingTimer->stop();
|
|
emit STP_disconnected();
|
|
break;
|
|
|
|
case stpProtocol_ns::packetType::SYNCAck:
|
|
if (_state == stpClient_ns::stpState::CONNECTED) {
|
|
#ifdef STP_DEBUG
|
|
qDebug() << _address.toString() << "(!!!) <SYNCAck> came when client is already connected";
|
|
#endif
|
|
} else {
|
|
_state = stpClient_ns::stpState::CONNECTED;
|
|
_pingTimer->start();
|
|
emit STP_connected();
|
|
}
|
|
break;
|
|
|
|
case stpProtocol_ns::packetType::SYNCReq:
|
|
// клиент не реагирует
|
|
break;
|
|
}
|
|
}
|