2021-02-03 20:00:40 +00:00
// Copyright 2021 Phil Taylor M0VSE
2021-02-05 10:45:19 +00:00
// This code is heavily based on "Kappanhang" by HA2NON, ES1AKOS and W6EL!
2021-02-03 20:00:40 +00:00
# include "udphandler.h"
2021-02-23 21:21:22 +00:00
# include "logcategories.h"
2021-02-07 18:46:47 +00:00
2021-03-01 19:53:12 +00:00
udpHandler : : udpHandler ( udpPreferences prefs ) :
2021-03-01 20:31:05 +00:00
controlPort ( prefs . controlLANPort ) ,
civPort ( 0 ) ,
audioPort ( 0 ) ,
rxSampleRate ( prefs . audioRXSampleRate ) ,
txSampleRate ( prefs . audioRXSampleRate ) ,
rxLatency ( prefs . audioRXLatency ) ,
txLatency ( prefs . audioTXLatency ) ,
rxCodec ( prefs . audioRXCodec ) ,
txCodec ( prefs . audioTXCodec ) ,
audioInputPort ( prefs . audioInput ) ,
2021-03-09 17:22:16 +00:00
audioOutputPort ( prefs . audioOutput ) ,
resampleQuality ( prefs . resampleQuality )
2021-03-01 19:53:12 +00:00
{
2021-03-01 20:31:05 +00:00
2021-02-13 23:25:24 +00:00
this - > port = this - > controlPort ;
2021-03-01 19:53:12 +00:00
this - > username = prefs . username ;
this - > password = prefs . password ;
qDebug ( logUdp ( ) ) < < " Starting udpHandler user: " < < username < < " rx latency: " < < rxLatency < < " tx latency: " < < txLatency < < " rx sample rate: " < < rxSampleRate < <
" rx codec: " < < rxCodec < < " tx sample rate: " < < txSampleRate < < " tx codec: " < < txCodec ;
2021-02-07 17:40:38 +00:00
2021-02-07 18:46:47 +00:00
// Try to set the IP address, if it is a hostname then perform a DNS lookup.
2021-03-01 19:53:12 +00:00
if ( ! radioIP . setAddress ( prefs . ipAddress ) )
2021-02-07 18:46:47 +00:00
{
2021-03-01 19:53:12 +00:00
QHostInfo remote = QHostInfo : : fromName ( prefs . ipAddress ) ;
2021-02-07 19:09:19 +00:00
foreach ( QHostAddress addr , remote . addresses ( ) )
2021-02-07 18:46:47 +00:00
{
2021-02-07 19:09:19 +00:00
if ( addr . protocol ( ) = = QAbstractSocket : : IPv4Protocol ) {
radioIP = addr ;
2021-03-01 19:53:12 +00:00
qDebug ( logUdp ( ) ) < < " Got IP Address : " < < prefs . ipAddress < < " : " < < addr . toString ( ) ;
2021-02-07 19:09:19 +00:00
break ;
}
2021-02-07 18:46:47 +00:00
}
2021-02-07 19:09:19 +00:00
if ( radioIP . isNull ( ) )
{
2021-03-01 19:53:12 +00:00
qDebug ( logUdp ( ) ) < < " Error obtaining IP Address for : " < < prefs . ipAddress < < " : " < < remote . errorString ( ) ;
2021-02-07 18:46:47 +00:00
return ;
}
}
2021-02-03 20:00:40 +00:00
// Convoluted way to find the external IP address, there must be a better way????
QString localhostname = QHostInfo : : localHostName ( ) ;
QList < QHostAddress > hostList = QHostInfo : : fromName ( localhostname ) . addresses ( ) ;
2021-02-07 18:46:47 +00:00
foreach ( const QHostAddress & address , hostList )
2021-02-04 19:53:48 +00:00
{
2021-02-07 18:46:47 +00:00
if ( address . protocol ( ) = = QAbstractSocket : : IPv4Protocol & & address . isLoopback ( ) = = false )
2021-02-04 19:53:48 +00:00
{
2021-02-04 06:00:13 +00:00
localIP = QHostAddress ( address . toString ( ) ) ;
2021-02-03 20:00:40 +00:00
}
}
2021-02-21 14:53:42 +00:00
// Set my computer name. Should this be configurable?
compName = " wfview " ;
}
void udpHandler : : init ( )
{
2021-02-13 23:25:24 +00:00
udpBase : : init ( ) ; // Perform UDP socket initialization.
2021-02-07 18:46:47 +00:00
2021-02-13 23:25:24 +00:00
// Connect socket to my dataReceived function.
QUdpSocket : : connect ( udp , & QUdpSocket : : readyRead , this , & udpHandler : : dataReceived ) ;
2021-02-07 18:46:47 +00:00
2021-02-13 23:25:24 +00:00
/*
Connect various timers
*/
2021-02-21 14:53:42 +00:00
tokenTimer = new QTimer ( ) ;
areYouThereTimer = new QTimer ( ) ;
pingTimer = new QTimer ( ) ;
idleTimer = new QTimer ( ) ;
2021-02-04 19:53:48 +00:00
2021-02-21 14:53:42 +00:00
connect ( tokenTimer , & QTimer : : timeout , this , std : : bind ( & udpHandler : : sendToken , this , 0x05 ) ) ;
2021-02-25 11:13:18 +00:00
connect ( areYouThereTimer , & QTimer : : timeout , this , std : : bind ( & udpBase : : sendControl , this , false , 0x03 , 0 ) ) ;
2021-02-21 14:53:42 +00:00
connect ( pingTimer , & QTimer : : timeout , this , & udpBase : : sendPing ) ;
connect ( idleTimer , & QTimer : : timeout , this , std : : bind ( & udpBase : : sendControl , this , true , 0 , 0 ) ) ;
2021-02-13 23:25:24 +00:00
2021-02-21 14:53:42 +00:00
// Start sending are you there packets - will be stopped once "I am here" received
areYouThereTimer - > start ( AREYOUTHERE_PERIOD ) ;
2021-02-03 20:00:40 +00:00
}
udpHandler : : ~ udpHandler ( )
{
2021-02-21 01:18:14 +00:00
if ( streamOpened ) {
2021-02-13 23:25:24 +00:00
if ( audio ! = Q_NULLPTR ) {
2021-02-03 20:00:40 +00:00
delete audio ;
2021-02-05 17:40:58 +00:00
}
2021-02-13 23:25:24 +00:00
if ( civ ! = Q_NULLPTR ) {
delete civ ;
2021-02-05 17:40:58 +00:00
}
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < " Sending token removal packet " ;
2021-02-13 23:25:24 +00:00
sendToken ( 0x01 ) ;
2021-02-25 17:53:01 +00:00
if ( tokenTimer ! = Q_NULLPTR )
{
tokenTimer - > stop ( ) ;
delete tokenTimer ;
}
if ( watchdogTimer ! = Q_NULLPTR )
{
watchdogTimer - > stop ( ) ;
delete watchdogTimer ;
}
2021-02-03 20:00:40 +00:00
}
}
2021-02-22 22:25:09 +00:00
2021-02-27 00:37:00 +00:00
void udpHandler : : changeLatency ( quint16 value )
2021-02-08 16:53:26 +00:00
{
2021-02-27 00:37:00 +00:00
emit haveChangeLatency ( value ) ;
2021-02-08 16:53:26 +00:00
}
2021-02-13 23:25:24 +00:00
void udpHandler : : receiveFromCivStream ( QByteArray data )
2021-02-03 20:00:40 +00:00
{
emit haveDataFromPort ( data ) ;
}
2021-03-01 19:53:12 +00:00
void udpHandler : : receiveAudioData ( const audioPacket & data )
2021-02-28 20:10:07 +00:00
{
emit haveAudioData ( data ) ;
}
2021-02-03 20:00:40 +00:00
void udpHandler : : receiveDataFromUserToRig ( QByteArray data )
{
2021-02-13 23:25:24 +00:00
if ( civ ! = Q_NULLPTR )
2021-02-05 17:40:58 +00:00
{
2021-02-13 23:25:24 +00:00
civ - > send ( data ) ;
2021-02-05 17:40:58 +00:00
}
2021-02-03 20:00:40 +00:00
}
2021-02-13 23:25:24 +00:00
void udpHandler : : dataReceived ( )
2021-02-03 20:00:40 +00:00
{
while ( udp - > hasPendingDatagrams ( ) ) {
2021-02-25 17:53:01 +00:00
lastReceived = QTime : : currentTime ( ) ;
2021-02-03 20:00:40 +00:00
QNetworkDatagram datagram = udp - > receiveDatagram ( ) ;
QByteArray r = datagram . data ( ) ;
switch ( r . length ( ) )
{
2021-02-20 18:29:23 +00:00
case ( CONTROL_SIZE ) : // control packet
2021-02-05 21:23:00 +00:00
{
2021-02-20 18:29:23 +00:00
control_packet_t in = ( control_packet_t ) r . constData ( ) ;
if ( in - > type = = 0x04 ) {
// If timer is active, stop it as they are obviously there!
2021-03-09 17:22:16 +00:00
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Received I am here from: " < < datagram . senderAddress ( ) ;
2021-02-21 14:53:42 +00:00
if ( areYouThereTimer - > isActive ( ) ) {
2021-02-20 18:29:23 +00:00
// send ping packets every second
2021-02-25 11:13:18 +00:00
areYouThereTimer - > stop ( ) ;
2021-02-21 14:53:42 +00:00
pingTimer - > start ( PING_PERIOD ) ;
idleTimer - > start ( IDLE_PERIOD ) ;
2021-02-05 17:40:58 +00:00
}
2021-02-14 07:15:49 +00:00
}
2021-02-20 18:29:23 +00:00
// This is "I am ready" in response to "Are you ready" so send login.
else if ( in - > type = = 0x06 )
2021-02-14 07:15:49 +00:00
{
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Received I am ready " ;
2021-02-20 18:29:23 +00:00
sendLogin ( ) ; // send login packet
2021-02-14 07:15:49 +00:00
}
2021-02-20 18:29:23 +00:00
break ;
}
case ( PING_SIZE ) : // ping packet
{
ping_packet_t in = ( ping_packet_t ) r . constData ( ) ;
if ( in - > type = = 0x07 & & in - > reply = = 0x01 & & streamOpened )
2021-02-14 07:15:49 +00:00
{
2021-02-20 18:29:23 +00:00
// This is a response to our ping request so measure latency
latency + = lastPingSentTime . msecsTo ( QDateTime : : currentDateTime ( ) ) ;
latency / = 2 ;
quint32 totalsent = packetsSent ;
2021-02-24 22:56:40 +00:00
quint32 totallost = packetsLost ;
2021-02-20 18:29:23 +00:00
if ( audio ! = Q_NULLPTR ) {
totalsent = totalsent + audio - > packetsSent ;
2021-02-24 22:56:40 +00:00
totallost = totallost + audio - > packetsLost ;
2021-02-20 18:29:23 +00:00
}
if ( civ ! = Q_NULLPTR ) {
totalsent = totalsent + civ - > packetsSent ;
2021-02-24 22:56:40 +00:00
totallost = totallost + civ - > packetsLost ;
2021-02-20 18:29:23 +00:00
}
2021-02-24 22:56:40 +00:00
emit haveNetworkStatus ( " rtt: " + QString : : number ( latency ) + " ms, loss: ( " + QString : : number ( totallost ) + " / " + QString : : number ( totalsent ) + " ) " ) ;
2021-02-03 20:00:40 +00:00
}
2021-02-20 18:29:23 +00:00
break ;
2021-02-03 20:00:40 +00:00
}
2021-02-20 18:29:23 +00:00
case ( TOKEN_SIZE ) : // Response to Token request
2021-02-03 20:00:40 +00:00
{
2021-02-20 18:29:23 +00:00
token_packet_t in = ( token_packet_t ) r . constData ( ) ;
2021-02-24 22:56:40 +00:00
if ( in - > res = = 0x05 & & in - > type ! = 0x01 )
2021-02-05 17:40:58 +00:00
{
2021-02-20 18:29:23 +00:00
if ( in - > response = = 0x0000 )
2021-02-05 17:40:58 +00:00
{
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Token renewal successful " ;
2021-02-21 14:53:42 +00:00
tokenTimer - > start ( TOKEN_RENEWAL ) ;
2021-02-20 18:29:23 +00:00
gotAuthOK = true ;
if ( ! streamOpened )
{
sendRequestStream ( ) ;
}
}
else if ( in - > response = = 0xffffffff )
{
qWarning ( ) < < this - > metaObject ( ) - > className ( ) < < " : Radio rejected token renewal, performing login " ;
remoteId = in - > sentid ;
2021-02-21 14:53:42 +00:00
tokRequest = in - > tokrequest ;
token = in - > token ;
2021-03-06 14:40:43 +00:00
streamOpened = false ;
sendRequestStream ( ) ;
2021-02-21 14:53:42 +00:00
// Got new token response
2021-03-06 14:40:43 +00:00
//sendToken(0x02); // Update it.
2021-02-20 18:29:23 +00:00
}
else
{
qWarning ( ) < < this - > metaObject ( ) - > className ( ) < < " : Unknown response to token renewal? " < < in - > response ;
2021-02-03 20:00:40 +00:00
}
2021-02-05 17:40:58 +00:00
}
2021-02-20 18:29:23 +00:00
break ;
}
case ( STATUS_SIZE ) : // Status packet
{
status_packet_t in = ( status_packet_t ) r . constData ( ) ;
2021-02-24 22:56:40 +00:00
if ( in - > type ! = 0x01 ) {
if ( in - > error = = 0x00ffffff & & ! streamOpened )
{
emit haveNetworkError ( radioIP . toString ( ) , " Auth failed, try rebooting the radio. " ) ;
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Auth failed, try rebooting the radio. " ;
}
else if ( in - > error = = 0x00000000 & & in - > disc = = 0x01 )
{
emit haveNetworkError ( radioIP . toString ( ) , " Got radio disconnected. " ) ;
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Got radio disconnected. " ;
if ( streamOpened ) {
// Close stream connections but keep connection open to the radio.
if ( audio ! = Q_NULLPTR ) {
delete audio ;
}
if ( civ ! = Q_NULLPTR ) {
delete civ ;
}
streamOpened = false ;
2021-02-21 14:53:42 +00:00
}
}
2021-03-01 19:53:12 +00:00
else {
civPort = qFromBigEndian ( in - > civport ) ;
audioPort = qFromBigEndian ( in - > audioport ) ;
}
2021-02-03 20:00:40 +00:00
}
2021-02-20 18:29:23 +00:00
break ;
2021-02-03 20:00:40 +00:00
}
2021-02-20 18:29:23 +00:00
case ( LOGIN_RESPONSE_SIZE ) : // Response to Login packet.
2021-02-03 20:00:40 +00:00
{
2021-02-20 18:29:23 +00:00
login_response_packet_t in = ( login_response_packet_t ) r . constData ( ) ;
2021-02-24 22:56:40 +00:00
if ( in - > type ! = 0x01 ) {
if ( in - > error = = 0xfeffffff )
2021-02-20 18:29:23 +00:00
{
2021-02-24 22:56:40 +00:00
emit haveNetworkStatus ( " Invalid Username/Password " ) ;
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Invalid Username/Password " ;
2021-02-20 18:29:23 +00:00
}
2021-02-24 22:56:40 +00:00
else if ( ! isAuthenticated )
2021-02-20 18:29:23 +00:00
{
2021-02-24 22:56:40 +00:00
if ( in - > tokrequest = = tokRequest )
{
emit haveNetworkStatus ( " Radio Login OK! " ) ;
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Received matching token response to our request " ;
token = in - > token ;
sendToken ( 0x02 ) ;
tokenTimer - > start ( TOKEN_RENEWAL ) ; // Start token request timer
isAuthenticated = true ;
}
else
{
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Token response did not match, sent: " < < tokRequest < < " got " < < in - > tokrequest ;
}
2021-02-20 18:29:23 +00:00
}
2021-02-24 22:56:40 +00:00
if ( ! strcmp ( in - > connection , " FTTH " ) )
{
highBandwidthConnection = true ;
}
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Detected connection speed " < < in - > connection ;
2021-02-03 20:00:40 +00:00
}
2021-02-20 18:29:23 +00:00
break ;
2021-02-03 20:00:40 +00:00
}
2021-02-20 18:29:23 +00:00
case ( CONNINFO_SIZE ) :
2021-02-05 17:40:58 +00:00
{
2021-02-20 18:29:23 +00:00
conninfo_packet_t in = ( conninfo_packet_t ) r . constData ( ) ;
2021-02-24 22:56:40 +00:00
if ( in - > type ! = 0x01 ) {
devName = in - > name ;
QHostAddress ip = QHostAddress ( qToBigEndian ( in - > ipaddress ) ) ;
if ( ! streamOpened & & in - > busy )
2021-02-20 18:29:23 +00:00
{
2021-02-24 22:56:40 +00:00
if ( in - > ipaddress ! = 0x00 & & strcmp ( in - > computer , compName . toLocal8Bit ( ) ) )
{
emit haveNetworkStatus ( devName + " in use by: " + in - > computer + " ( " + ip . toString ( ) + " ) " ) ;
sendControl ( false , 0x00 , in - > seq ) ; // Respond with an idle
}
else {
civ = new udpCivData ( localIP , radioIP , civPort ) ;
2021-03-09 17:22:16 +00:00
audio = new udpAudio ( localIP , radioIP , audioPort , rxLatency , txLatency , rxSampleRate , rxCodec , txSampleRate , txCodec , audioOutputPort , audioInputPort , resampleQuality ) ;
2021-02-21 01:18:14 +00:00
2021-02-24 22:56:40 +00:00
QObject : : connect ( civ , SIGNAL ( receive ( QByteArray ) ) , this , SLOT ( receiveFromCivStream ( QByteArray ) ) ) ;
2021-03-01 19:53:12 +00:00
QObject : : connect ( audio , SIGNAL ( haveAudioData ( audioPacket ) ) , this , SLOT ( receiveAudioData ( audioPacket ) ) ) ;
2021-03-01 20:31:05 +00:00
QObject : : connect ( this , SIGNAL ( haveChangeLatency ( quint16 ) ) , audio , SLOT ( changeLatency ( quint16 ) ) ) ;
2021-02-05 20:26:18 +00:00
2021-02-24 22:56:40 +00:00
streamOpened = true ;
2021-02-03 20:00:40 +00:00
2021-02-24 22:56:40 +00:00
emit haveNetworkStatus ( devName ) ;
2021-02-21 01:18:14 +00:00
2021-02-24 22:56:40 +00:00
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " Got serial and audio request success, device name: " < < devName ;
// Stuff can change in the meantime because of a previous login...
remoteId = in - > sentid ;
myId = in - > rcvdid ;
tokRequest = in - > tokrequest ;
token = in - > token ;
}
2021-02-20 18:29:23 +00:00
}
2021-02-24 22:56:40 +00:00
else if ( ! streamOpened & & ! in - > busy )
{
emit haveNetworkStatus ( devName + " available " ) ;
2021-02-21 01:18:14 +00:00
2021-02-24 22:56:40 +00:00
identa = in - > identa ;
identb = in - > identb ;
2021-02-21 01:18:14 +00:00
2021-02-24 22:56:40 +00:00
sendRequestStream ( ) ;
}
2021-02-25 17:53:01 +00:00
else if ( streamOpened )
/* If another client connects/disconnects from the server, the server will emit
a CONNINFO packet , send our details to confirm we still want the stream */
{
// Received while stream is open.
sendRequestStream ( ) ;
}
2021-02-20 18:29:23 +00:00
}
break ;
2021-02-03 20:00:40 +00:00
}
2021-02-20 18:29:23 +00:00
case ( CAPABILITIES_SIZE ) :
{
capabilities_packet_t in = ( capabilities_packet_t ) r . constData ( ) ;
2021-02-24 22:56:40 +00:00
if ( in - > type ! = 0x01 )
{
audioType = in - > audio ;
devName = in - > name ;
//replyId = r.mid(0x42, 16);
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " Received radio capabilities, Name: " < <
devName < < " Audio: " < <
audioType ;
}
2021-02-20 18:29:23 +00:00
break ;
}
2021-02-03 20:00:40 +00:00
}
2021-02-13 23:25:24 +00:00
udpBase : : dataReceived ( r ) ; // Call parent function to process the rest.
2021-02-04 20:09:09 +00:00
r . clear ( ) ;
datagram . clear ( ) ;
2021-02-03 20:00:40 +00:00
}
return ;
}
2021-02-20 18:29:23 +00:00
void udpHandler : : sendRequestStream ( )
2021-02-03 20:00:40 +00:00
{
2021-02-20 18:29:23 +00:00
2021-02-15 19:28:17 +00:00
QByteArray usernameEncoded ;
passcode ( username , usernameEncoded ) ;
2021-02-20 18:29:23 +00:00
conninfo_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
p . len = sizeof ( p ) ;
p . sentid = myId ;
p . rcvdid = remoteId ;
p . code = 0x0180 ;
p . res = 0x03 ;
2021-02-23 20:48:53 +00:00
p . commoncap = 0x8010 ;
2021-02-20 18:29:23 +00:00
p . identa = identa ;
p . identb = identb ;
2021-03-06 14:40:43 +00:00
p . innerseq = authSeq + + ;
2021-02-20 18:29:23 +00:00
p . tokrequest = tokRequest ;
p . token = token ;
2021-02-21 01:18:14 +00:00
memcpy ( & p . name , devName . toLocal8Bit ( ) . constData ( ) , devName . length ( ) ) ;
2021-02-20 18:29:23 +00:00
p . rxenable = 1 ;
p . txenable = 1 ;
p . rxcodec = rxCodec ;
p . txcodec = txCodec ;
2021-02-21 15:06:27 +00:00
memcpy ( & p . username , usernameEncoded . constData ( ) , usernameEncoded . length ( ) ) ;
2021-02-20 18:29:23 +00:00
p . rxsample = qToBigEndian ( ( quint32 ) rxSampleRate ) ;
p . txsample = qToBigEndian ( ( quint32 ) txSampleRate ) ;
p . civport = qToBigEndian ( ( quint32 ) civPort ) ;
p . audioport = qToBigEndian ( ( quint32 ) audioPort ) ;
2021-02-27 00:37:00 +00:00
p . txbuffer = qToBigEndian ( ( quint32 ) txLatency ) ;
2021-03-09 17:22:16 +00:00
p . convert = 1 ;
2021-02-20 18:29:23 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ) ;
2021-02-13 23:25:24 +00:00
return ;
2021-02-03 20:00:40 +00:00
}
2021-02-14 07:53:55 +00:00
void udpHandler : : sendAreYouThere ( )
{
if ( areYouThereCounter = = 20 )
{
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Radio not responding. " ;
2021-02-14 07:53:55 +00:00
emit haveNetworkStatus ( " Radio not responding! " ) ;
}
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Sending Are You There... " ;
2021-02-18 15:54:26 +00:00
2021-02-14 07:53:55 +00:00
areYouThereCounter + + ;
2021-02-18 15:54:26 +00:00
udpBase : : sendControl ( false , 0x03 , 0x00 ) ;
2021-02-14 07:53:55 +00:00
}
2021-02-13 23:25:24 +00:00
void udpHandler : : sendLogin ( ) // Only used on control stream.
2021-02-03 20:00:40 +00:00
{
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Sending login packet " ;
2021-02-13 23:25:24 +00:00
2021-02-20 18:29:23 +00:00
tokRequest = static_cast < quint16 > ( rand ( ) | rand ( ) < < 8 ) ; // Generate random token request.
2021-02-15 19:28:17 +00:00
QByteArray usernameEncoded ;
QByteArray passwordEncoded ;
passcode ( username , usernameEncoded ) ;
passcode ( password , passwordEncoded ) ;
2021-02-03 20:00:40 +00:00
2021-02-20 18:29:23 +00:00
login_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
p . len = sizeof ( p ) ;
p . sentid = myId ;
p . rcvdid = remoteId ;
p . code = 0x0170 ; // Not sure what this is?
2021-03-06 14:40:43 +00:00
p . innerseq = authSeq + + ;
2021-02-20 18:29:23 +00:00
p . tokrequest = tokRequest ;
memcpy ( p . username , usernameEncoded . constData ( ) , usernameEncoded . length ( ) ) ;
memcpy ( p . password , passwordEncoded . constData ( ) , passwordEncoded . length ( ) ) ;
2021-02-21 01:18:14 +00:00
memcpy ( p . name , compName . toLocal8Bit ( ) . constData ( ) , compName . length ( ) ) ;
2021-02-03 20:00:40 +00:00
2021-02-20 18:29:23 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ) ;
2021-02-13 23:25:24 +00:00
return ;
2021-02-03 20:00:40 +00:00
}
2021-02-13 23:25:24 +00:00
void udpHandler : : sendToken ( uint8_t magic )
2021-02-03 20:00:40 +00:00
{
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " Sending Token request: " < < magic ;
2021-02-03 20:00:40 +00:00
2021-02-20 18:29:23 +00:00
token_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
p . len = sizeof ( p ) ;
p . sentid = myId ;
p . rcvdid = remoteId ;
p . code = 0x0130 ; // Not sure what this is?
p . res = magic ;
2021-03-06 14:40:43 +00:00
p . innerseq = authSeq + + ;
2021-02-20 18:29:23 +00:00
p . tokrequest = tokRequest ;
p . token = token ;
2021-02-14 15:30:34 +00:00
2021-02-20 18:29:23 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ) ;
2021-02-27 09:34:56 +00:00
// The radio should request a repeat of the token renewal packet via retransmission!
2021-02-24 22:56:40 +00:00
//tokenTimer->start(100); // Set 100ms timer for retry (this will be cancelled if a response is received)
2021-02-13 23:25:24 +00:00
return ;
2021-02-03 20:00:40 +00:00
}
2021-02-13 23:25:24 +00:00
// Class that manages all Civ Data to/from the rig
udpCivData : : udpCivData ( QHostAddress local , QHostAddress ip , quint16 civPort )
2021-02-05 17:40:58 +00:00
{
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < " Starting udpCivData " ;
2021-02-04 19:53:48 +00:00
localIP = local ;
2021-02-13 23:25:24 +00:00
port = civPort ;
2021-02-03 20:00:40 +00:00
radioIP = ip ;
2021-02-13 23:25:24 +00:00
udpBase : : init ( ) ; // Perform connection
QUdpSocket : : connect ( udp , & QUdpSocket : : readyRead , this , & udpCivData : : dataReceived ) ;
2021-02-03 20:00:40 +00:00
2021-02-18 15:54:26 +00:00
sendControl ( false , 0x03 , 0x00 ) ; // First connect packet
2021-02-13 23:25:24 +00:00
/*
Connect various timers
*/
2021-02-21 14:53:42 +00:00
pingTimer = new QTimer ( ) ;
idleTimer = new QTimer ( ) ;
2021-02-25 11:13:18 +00:00
areYouThereTimer = new QTimer ( ) ;
2021-02-25 17:53:01 +00:00
startCivDataTimer = new QTimer ( ) ;
watchdogTimer = new QTimer ( ) ;
2021-02-21 14:53:42 +00:00
connect ( pingTimer , & QTimer : : timeout , this , & udpBase : : sendPing ) ;
2021-02-25 17:53:01 +00:00
connect ( watchdogTimer , & QTimer : : timeout , this , & udpCivData : : watchdog ) ;
2021-02-21 14:53:42 +00:00
connect ( idleTimer , & QTimer : : timeout , this , std : : bind ( & udpBase : : sendControl , this , true , 0 , 0 ) ) ;
2021-02-25 17:53:01 +00:00
connect ( startCivDataTimer , & QTimer : : timeout , this , std : : bind ( & udpCivData : : sendOpenClose , this , false ) ) ;
2021-02-25 11:13:18 +00:00
connect ( areYouThereTimer , & QTimer : : timeout , this , std : : bind ( & udpBase : : sendControl , this , false , 0x03 , 0 ) ) ;
2021-02-25 17:53:01 +00:00
watchdogTimer - > start ( WATCHDOG_PERIOD ) ;
2021-02-25 11:13:18 +00:00
// Start sending are you there packets - will be stopped once "I am here" received
2021-02-13 23:25:24 +00:00
// send ping packets every 100 ms (maybe change to less frequent?)
2021-02-21 14:53:42 +00:00
pingTimer - > start ( PING_PERIOD ) ;
2021-02-13 23:25:24 +00:00
// Send idle packets every 100ms, this timer will be reset everytime a non-idle packet is sent.
2021-02-21 14:53:42 +00:00
idleTimer - > start ( IDLE_PERIOD ) ;
2021-02-25 11:13:18 +00:00
areYouThereTimer - > start ( AREYOUTHERE_PERIOD ) ;
2021-02-03 20:00:40 +00:00
}
2021-02-25 17:53:01 +00:00
udpCivData : : ~ udpCivData ( )
{
2021-02-13 23:25:24 +00:00
sendOpenClose ( true ) ;
2021-02-25 17:53:01 +00:00
if ( startCivDataTimer ! = Q_NULLPTR )
{
startCivDataTimer - > stop ( ) ;
delete startCivDataTimer ;
startCivDataTimer = Q_NULLPTR ;
}
}
void udpCivData : : watchdog ( )
{
static bool alerted = false ;
if ( lastReceived . msecsTo ( QTime : : currentTime ( ) ) > 500 )
{
if ( ! alerted ) {
qDebug ( logUdp ( ) ) < < " CIV Watchdog: no CIV data received for 500ms, requesting data start. " ;
if ( startCivDataTimer ! = Q_NULLPTR )
{
startCivDataTimer - > start ( 100 ) ;
}
alerted = true ;
}
}
else
{
alerted = false ;
}
2021-02-13 23:25:24 +00:00
}
2021-02-03 20:00:40 +00:00
2021-02-13 23:25:24 +00:00
void udpCivData : : send ( QByteArray d )
2021-02-03 20:00:40 +00:00
{
2021-02-23 21:21:22 +00:00
// qDebug(logUdp()) << "Sending: (" << d.length() << ") " << d;
2021-02-20 18:29:23 +00:00
data_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
p . len = sizeof ( p ) ;
p . sentid = myId ;
p . rcvdid = remoteId ;
p . reply = ( char ) 0xc1 ;
p . datalen = d . length ( ) ;
p . sendseq = qToBigEndian ( sendSeqB ) ; // THIS IS BIG ENDIAN!
QByteArray t = QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ;
2021-02-03 20:00:40 +00:00
t . append ( d ) ;
2021-02-13 23:25:24 +00:00
sendTrackedPacket ( t ) ;
2021-02-03 20:00:40 +00:00
sendSeqB + + ;
2021-02-13 23:25:24 +00:00
return ;
2021-02-03 20:00:40 +00:00
}
2021-02-13 23:25:24 +00:00
void udpCivData : : sendOpenClose ( bool close )
2021-02-03 20:00:40 +00:00
{
2021-02-25 17:53:01 +00:00
uint8_t magic = 0x04 ;
2021-02-03 20:00:40 +00:00
2021-02-05 17:40:58 +00:00
if ( close )
{
2021-02-03 20:00:40 +00:00
magic = 0x00 ;
2021-02-05 17:40:58 +00:00
}
2021-02-03 20:00:40 +00:00
2021-02-21 01:18:14 +00:00
openclose_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
p . len = sizeof ( p ) ;
p . sentid = myId ;
p . rcvdid = remoteId ;
p . data = 0x01c0 ; // Not sure what other values are available:
p . sendseq = qToBigEndian ( sendSeqB ) ;
p . magic = magic ;
2021-02-03 20:00:40 +00:00
sendSeqB + + ;
2021-02-21 01:18:14 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ) ;
2021-02-13 23:25:24 +00:00
return ;
2021-02-03 20:00:40 +00:00
}
2021-02-13 23:25:24 +00:00
void udpCivData : : dataReceived ( )
2021-02-03 20:00:40 +00:00
{
2021-02-20 18:29:23 +00:00
while ( udp - > hasPendingDatagrams ( ) )
{
2021-02-03 20:00:40 +00:00
QNetworkDatagram datagram = udp - > receiveDatagram ( ) ;
2021-02-23 21:21:22 +00:00
//qDebug(logUdp()) << "Received: " << datagram.data();
2021-02-03 20:00:40 +00:00
QByteArray r = datagram . data ( ) ;
switch ( r . length ( ) )
{
2021-02-20 18:29:23 +00:00
case ( CONTROL_SIZE ) : // Control packet
2021-02-03 20:00:40 +00:00
{
2021-02-20 18:29:23 +00:00
control_packet_t in = ( control_packet_t ) r . constData ( ) ;
2021-02-25 11:13:18 +00:00
if ( in - > type = = 0x04 )
{
areYouThereTimer - > stop ( ) ;
}
else if ( in - > type = = 0x06 )
2021-02-20 18:29:23 +00:00
{
// Update remoteId
remoteId = in - > sentid ;
2021-02-25 17:53:01 +00:00
// Manually send a CIV start request and start the timer if it isn't received.
// The timer will be stopped as soon as valid CIV data is received.
2021-02-20 18:29:23 +00:00
sendOpenClose ( false ) ;
2021-02-25 17:53:01 +00:00
if ( startCivDataTimer ! = Q_NULLPTR ) {
startCivDataTimer - > start ( 100 ) ;
}
2021-02-05 20:26:18 +00:00
}
2021-02-20 20:23:21 +00:00
break ;
2021-02-20 18:29:23 +00:00
}
default :
{
2021-02-28 20:10:07 +00:00
if ( r . length ( ) > 21 ) {
data_packet_t in = ( data_packet_t ) r . constData ( ) ;
if ( in - > type ! = 0x01 ) {
// Process this packet, any re-transmit requests will happen later.
//uint16_t gotSeq = qFromLittleEndian<quint16>(r.mid(6, 2));
// We have received some Civ data so stop sending Start packets!
if ( startCivDataTimer ! = Q_NULLPTR ) {
startCivDataTimer - > stop ( ) ;
}
lastReceived = QTime : : currentTime ( ) ;
2021-02-28 20:15:34 +00:00
if ( quint16 ( in - > datalen + 0x15 ) = = ( quint16 ) in - > len )
2021-02-28 20:10:07 +00:00
{
emit receive ( r . mid ( 0x15 ) ) ;
}
2021-02-20 18:29:23 +00:00
}
}
break ;
2021-02-03 20:00:40 +00:00
}
}
2021-02-13 23:25:24 +00:00
udpBase : : dataReceived ( r ) ; // Call parent function to process the rest.
2021-02-04 20:09:09 +00:00
r . clear ( ) ;
datagram . clear ( ) ;
2021-02-03 20:00:40 +00:00
}
}
// Audio stream
2021-03-09 17:22:16 +00:00
udpAudio : : udpAudio ( QHostAddress local , QHostAddress ip , quint16 audioPort , quint16 rxlatency , quint16 txlatency , quint16 rxsample , quint8 rxcodec , quint16 txsample , quint8 txcodec , QString outputPort , QString inputPort , quint8 resampleQuality )
2021-02-03 20:00:40 +00:00
{
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < " Starting udpAudio " ;
2021-02-09 12:43:28 +00:00
this - > localIP = local ;
2021-02-13 23:25:24 +00:00
this - > port = audioPort ;
2021-02-09 12:43:28 +00:00
this - > radioIP = ip ;
2021-02-27 00:37:00 +00:00
this - > rxLatency = rxlatency ;
this - > txLatency = txlatency ;
2021-02-09 12:43:28 +00:00
this - > rxSampleRate = rxsample ;
this - > txSampleRate = txsample ;
this - > rxCodec = rxcodec ;
this - > txCodec = txcodec ;
2021-02-03 20:00:40 +00:00
2021-02-04 20:20:23 +00:00
init ( ) ; // Perform connection
2021-02-04 19:53:48 +00:00
2021-02-13 23:25:24 +00:00
QUdpSocket : : connect ( udp , & QUdpSocket : : readyRead , this , & udpAudio : : dataReceived ) ;
2021-02-03 20:00:40 +00:00
2021-02-12 14:28:55 +00:00
/*
0x72 is RX audio codec
0x73 is TX audio codec ( only single channel options )
0x01 uLaw 1 ch 8 bit
0x02 PCM 1 ch 8 bit
0x04 PCM 1 ch 16 bit
0x08 PCM 2 ch 8 bit
0x10 PCM 2 ch 16 bit
0x20 uLaw 2 ch 8 bit
*/
if ( rxCodec = = 0x01 | | rxCodec = = 0x20 ) {
2021-02-09 12:43:28 +00:00
rxIsUlawCodec = true ;
2021-02-12 14:28:55 +00:00
}
if ( rxCodec = = 0x08 | | rxCodec = = 0x10 | | rxCodec = = 0x20 ) {
2021-02-09 12:43:28 +00:00
rxChannelCount = 2 ;
2021-02-12 14:28:55 +00:00
}
if ( rxCodec = = 0x04 | | rxCodec = = 0x10 ) {
rxNumSamples = 16 ;
}
2021-02-03 20:00:40 +00:00
2021-02-11 19:18:35 +00:00
rxaudio = new audioHandler ( ) ;
2021-02-08 08:31:48 +00:00
rxAudioThread = new QThread ( this ) ;
rxaudio - > moveToThread ( rxAudioThread ) ;
2021-03-09 17:22:16 +00:00
connect ( this , SIGNAL ( setupRxAudio ( quint8 , quint8 , quint16 , quint16 , bool , bool , QString , quint8 ) ) , rxaudio , SLOT ( init ( quint8 , quint8 , quint16 , quint16 , bool , bool , QString , quint8 ) ) ) ;
2021-02-27 00:37:00 +00:00
2021-03-01 19:53:12 +00:00
qRegisterMetaType < audioPacket > ( ) ;
connect ( this , SIGNAL ( haveAudioData ( audioPacket ) ) , rxaudio , SLOT ( incomingAudio ( audioPacket ) ) ) ;
2021-02-27 00:37:00 +00:00
connect ( this , SIGNAL ( haveChangeLatency ( quint16 ) ) , rxaudio , SLOT ( changeLatency ( quint16 ) ) ) ;
2021-02-08 10:22:20 +00:00
connect ( rxAudioThread , SIGNAL ( finished ( ) ) , rxaudio , SLOT ( deleteLater ( ) ) ) ;
2021-02-08 08:31:48 +00:00
2021-02-11 19:18:35 +00:00
if ( txCodec = = 0x01 )
txIsUlawCodec = true ;
2021-02-12 14:28:55 +00:00
else if ( txCodec = = 0x04 )
txNumSamples = 16 ;
2021-02-11 19:18:35 +00:00
txChannelCount = 1 ; // Only 1 channel is supported.
txaudio = new audioHandler ( ) ;
txAudioThread = new QThread ( this ) ;
txaudio - > moveToThread ( txAudioThread ) ;
2021-03-09 17:22:16 +00:00
connect ( this , SIGNAL ( setupTxAudio ( quint8 , quint8 , quint16 , quint16 , bool , bool , QString , quint8 ) ) , txaudio , SLOT ( init ( quint8 , quint8 , quint16 , quint16 , bool , bool , QString , quint8 ) ) ) ;
2021-02-11 19:18:35 +00:00
connect ( txAudioThread , SIGNAL ( finished ( ) ) , txaudio , SLOT ( deleteLater ( ) ) ) ;
2021-02-08 11:14:17 +00:00
rxAudioThread - > start ( ) ;
2021-02-11 19:18:35 +00:00
txAudioThread - > start ( ) ;
2021-02-18 15:54:26 +00:00
sendControl ( false , 0x03 , 0x00 ) ; // First connect packet
2021-02-13 23:25:24 +00:00
2021-02-21 14:53:42 +00:00
pingTimer = new QTimer ( ) ;
connect ( pingTimer , & QTimer : : timeout , this , & udpBase : : sendPing ) ;
pingTimer - > start ( PING_PERIOD ) ; // send ping packets every 100ms
2021-02-13 23:25:24 +00:00
2021-03-09 17:22:16 +00:00
emit setupTxAudio ( txNumSamples , txChannelCount , txSampleRate , txLatency , txIsUlawCodec , true , inputPort , resampleQuality ) ;
emit setupRxAudio ( rxNumSamples , rxChannelCount , rxSampleRate , txLatency , rxIsUlawCodec , false , outputPort , resampleQuality ) ;
2021-02-14 07:15:49 +00:00
2021-02-25 17:53:01 +00:00
watchdogTimer = new QTimer ( ) ;
connect ( watchdogTimer , & QTimer : : timeout , this , & udpAudio : : watchdog ) ;
watchdogTimer - > start ( WATCHDOG_PERIOD ) ;
2021-02-21 14:53:42 +00:00
txAudioTimer = new QTimer ( ) ;
txAudioTimer - > setTimerType ( Qt : : PreciseTimer ) ;
connect ( txAudioTimer , & QTimer : : timeout , this , & udpAudio : : sendTxAudio ) ;
2021-02-25 11:13:18 +00:00
areYouThereTimer = new QTimer ( ) ;
connect ( areYouThereTimer , & QTimer : : timeout , this , std : : bind ( & udpBase : : sendControl , this , false , 0x03 , 0 ) ) ;
areYouThereTimer - > start ( AREYOUTHERE_PERIOD ) ;
2021-02-03 20:00:40 +00:00
}
2021-02-05 17:40:58 +00:00
udpAudio : : ~ udpAudio ( )
{
2021-02-21 14:53:42 +00:00
if ( txAudioTimer ! = Q_NULLPTR )
2021-02-13 23:25:24 +00:00
{
2021-02-21 14:53:42 +00:00
txAudioTimer - > stop ( ) ;
delete txAudioTimer ;
2021-02-13 23:25:24 +00:00
}
2021-02-08 10:22:20 +00:00
if ( rxAudioThread ) {
rxAudioThread - > quit ( ) ;
rxAudioThread - > wait ( ) ;
2021-02-08 08:31:48 +00:00
}
2021-02-13 23:25:24 +00:00
2021-02-11 19:18:35 +00:00
if ( txAudioThread ) {
txAudioThread - > quit ( ) ;
txAudioThread - > wait ( ) ;
}
}
2021-02-25 17:53:01 +00:00
void udpAudio : : watchdog ( )
{
static bool alerted = false ;
if ( lastReceived . msecsTo ( QTime : : currentTime ( ) ) > 500 )
{
if ( ! alerted ) {
/* Just log it at the moment, maybe try signalling the control channel that it needs to
try requesting civ / audio again ? */
qDebug ( logUdp ( ) ) < < " Audio Watchdog: no audio data received for 500ms, restart required " ;
alerted = true ;
}
}
else
{
alerted = false ;
}
}
2021-02-12 20:42:56 +00:00
2021-02-12 23:56:02 +00:00
void udpAudio : : sendTxAudio ( )
2021-02-11 19:18:35 +00:00
{
2021-02-18 15:54:26 +00:00
2021-02-21 14:53:42 +00:00
if ( txaudio - > isChunkAvailable ( ) ) {
2021-02-13 11:04:26 +00:00
QByteArray audio ;
txaudio - > getNextAudioChunk ( audio ) ;
2021-02-20 20:19:18 +00:00
int counter = 1 ;
int len = 0 ;
2021-02-21 14:53:42 +00:00
2021-02-20 20:19:18 +00:00
while ( len < audio . length ( ) ) {
QByteArray partial = audio . mid ( len , 1364 ) ;
2021-02-28 20:10:07 +00:00
audio_packet p ;
2021-02-20 18:29:23 +00:00
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
2021-02-28 20:10:07 +00:00
p . len = sizeof ( p ) + partial . length ( ) ;
2021-02-20 18:29:23 +00:00
p . sentid = myId ;
p . rcvdid = remoteId ;
2021-03-09 17:22:16 +00:00
if ( partial . length ( ) = = 0xa0 ) {
p . ident = 0x9781 ;
}
else {
p . ident = 0x0080 ; // TX audio is always this?
}
2021-02-20 20:19:18 +00:00
p . datalen = ( quint16 ) qToBigEndian ( ( quint16 ) partial . length ( ) ) ;
2021-02-21 14:53:42 +00:00
p . sendseq = ( quint16 ) qToBigEndian ( ( quint16 ) sendAudioSeq ) ; // THIS IS BIG ENDIAN!
2021-02-20 18:29:23 +00:00
QByteArray tx = QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ;
2021-02-12 23:56:02 +00:00
tx . append ( partial ) ;
2021-02-20 20:19:18 +00:00
len = len + partial . length ( ) ;
2021-02-23 21:21:22 +00:00
//qDebug(logUdp()) << "Sending audio packet length: " << tx.length();
2021-02-13 23:25:24 +00:00
sendTrackedPacket ( tx ) ;
2021-02-12 23:56:02 +00:00
sendAudioSeq + + ;
2021-02-20 20:19:18 +00:00
counter + + ;
2021-02-12 23:56:02 +00:00
}
2021-02-13 11:04:26 +00:00
}
2021-02-05 17:40:58 +00:00
}
2021-02-03 20:00:40 +00:00
2021-02-27 00:37:00 +00:00
void udpAudio : : changeLatency ( quint16 value )
2021-02-08 16:53:26 +00:00
{
2021-02-27 00:37:00 +00:00
emit haveChangeLatency ( value ) ;
2021-02-08 16:53:26 +00:00
}
2021-02-12 20:42:56 +00:00
2021-02-13 23:25:24 +00:00
void udpAudio : : dataReceived ( )
2021-02-03 20:00:40 +00:00
{
while ( udp - > hasPendingDatagrams ( ) ) {
QNetworkDatagram datagram = udp - > receiveDatagram ( ) ;
2021-02-23 21:21:22 +00:00
//qDebug(logUdp()) << "Received: " << datagram.data();
2021-02-03 20:00:40 +00:00
QByteArray r = datagram . data ( ) ;
switch ( r . length ( ) )
{
2021-02-24 22:56:40 +00:00
case ( 16 ) : // Response to control packet handled in udpBase
{
2021-02-25 11:13:18 +00:00
control_packet_t in = ( control_packet_t ) r . constData ( ) ;
if ( in - > type = = 0x04 )
{
txAudioTimer - > start ( TXAUDIO_PERIOD ) ;
}
2021-02-24 22:56:40 +00:00
break ;
}
default :
{
/* Audio packets start as follows:
PCM 16 bit and PCM8 / uLAW stereo : 0x44 , 0x02 for first packet and 0x6c , 0x05 for second .
uLAW 8 bit / PCM 8 bit 0xd8 , 0x03 for all packets
PCM 16 bit stereo 0x6c , 0x05 first & second 0x70 , 0x04 third
2021-02-09 12:43:28 +00:00
2021-02-24 22:56:40 +00:00
*/
control_packet_t in = ( control_packet_t ) r . constData ( ) ;
2021-03-09 17:22:16 +00:00
if ( in - > type ! = 0x01 & & in - > len > = 0xAC ) {
// 0xac is the smallest possible audio packet.
lastReceived = QTime : : currentTime ( ) ;
audioPacket tempAudio ;
tempAudio . seq = in - > seq ;
tempAudio . time = lastReceived ;
tempAudio . sent = 0 ;
tempAudio . datain = r . mid ( 0x18 ) ;
// Prefer signal/slot to forward audio as it is thread/safe
// Need to do more testing but latency appears fine.
emit haveAudioData ( tempAudio ) ;
//rxaudio->incomingAudio(tempAudio);
2021-02-24 22:56:40 +00:00
}
break ;
2021-02-03 20:00:40 +00:00
}
2021-02-20 18:29:23 +00:00
}
2021-02-27 00:37:00 +00:00
2021-02-13 23:25:24 +00:00
udpBase : : dataReceived ( r ) ; // Call parent function to process the rest.
2021-02-04 20:09:09 +00:00
r . clear ( ) ;
datagram . clear ( ) ;
2021-02-03 20:00:40 +00:00
}
}
2021-02-04 20:20:23 +00:00
void udpBase : : init ( )
2021-02-04 19:53:48 +00:00
{
2021-02-20 18:29:23 +00:00
timeStarted . start ( ) ;
2021-02-04 19:53:48 +00:00
udp = new QUdpSocket ( this ) ;
udp - > bind ( ) ; // Bind to random port.
localPort = udp - > localPort ( ) ;
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < " UDP Stream bound to local port: " < < localPort < < " remote port: " < < port ;
2021-02-04 19:53:48 +00:00
uint32_t addr = localIP . toIPv4Address ( ) ;
2021-02-13 23:25:24 +00:00
myId = ( addr > > 8 & 0xff ) < < 24 | ( addr & 0xff ) < < 16 | ( localPort & 0xffff ) ;
2021-02-27 00:37:00 +00:00
retransmitTimer = new QTimer ( ) ;
connect ( retransmitTimer , & QTimer : : timeout , this , & udpBase : : sendRetransmitRequest ) ;
retransmitTimer - > start ( RETRANSMIT_PERIOD ) ;
2021-02-04 19:53:48 +00:00
}
2021-02-13 23:25:24 +00:00
2021-02-04 19:53:48 +00:00
udpBase : : ~ udpBase ( )
{
2021-02-23 21:21:22 +00:00
qDebug ( logUdp ( ) ) < < " Closing UDP stream : " < < radioIP . toString ( ) < < " : " < < port ;
2021-02-07 12:59:41 +00:00
if ( udp ! = Q_NULLPTR ) {
2021-02-18 15:54:26 +00:00
sendControl ( false , 0x05 , 0x00 ) ; // Send disconnect
2021-02-04 19:53:48 +00:00
udp - > close ( ) ;
delete udp ;
}
2021-02-25 17:53:01 +00:00
if ( areYouThereTimer ! = Q_NULLPTR )
{
areYouThereTimer - > stop ( ) ;
delete areYouThereTimer ;
}
2021-02-21 14:53:42 +00:00
if ( pingTimer ! = Q_NULLPTR )
2021-02-07 12:59:41 +00:00
{
2021-02-21 14:53:42 +00:00
pingTimer - > stop ( ) ;
delete pingTimer ;
2021-02-07 12:59:41 +00:00
}
2021-02-21 14:53:42 +00:00
if ( idleTimer ! = Q_NULLPTR )
2021-02-07 12:59:41 +00:00
{
2021-02-21 14:53:42 +00:00
idleTimer - > stop ( ) ;
delete idleTimer ;
2021-02-07 12:59:41 +00:00
}
2021-02-27 00:37:00 +00:00
if ( retransmitTimer ! = Q_NULLPTR )
{
retransmitTimer - > stop ( ) ;
delete retransmitTimer ;
}
2021-02-25 17:53:01 +00:00
2021-02-21 14:53:42 +00:00
pingTimer = Q_NULLPTR ;
idleTimer = Q_NULLPTR ;
2021-02-25 17:53:01 +00:00
areYouThereTimer = Q_NULLPTR ;
2021-02-27 00:37:00 +00:00
retransmitTimer = Q_NULLPTR ;
2021-02-21 14:53:42 +00:00
2021-02-04 19:53:48 +00:00
}
2021-02-03 20:00:40 +00:00
// Base class!
2021-02-13 23:25:24 +00:00
void udpBase : : dataReceived ( QByteArray r )
2021-02-04 18:52:00 +00:00
{
2021-02-22 22:25:09 +00:00
if ( r . length ( ) < 0x10 )
{
return ; // Packet too small do to anything with?
}
2021-02-04 18:52:00 +00:00
switch ( r . length ( ) )
{
2021-02-20 18:29:23 +00:00
case ( CONTROL_SIZE ) : // Empty response used for simple comms and retransmit requests.
{
control_packet_t in = ( control_packet_t ) r . constData ( ) ;
2021-02-24 22:56:40 +00:00
if ( in - > type = = 0x01 )
2021-02-04 18:52:00 +00:00
{
2021-03-03 09:50:15 +00:00
QMutexLocker txlocker ( & txBufferMutex ) ;
2021-02-24 22:56:40 +00:00
// Single packet request
2021-02-22 22:25:09 +00:00
packetsLost + + ;
2021-02-23 20:48:53 +00:00
auto match = std : : find_if ( txSeqBuf . begin ( ) , txSeqBuf . end ( ) , [ & cs = in - > seq ] ( SEQBUFENTRY & s ) {
2021-02-22 22:25:09 +00:00
return s . seqNum = = cs ;
} ) ;
2021-02-23 20:48:53 +00:00
if ( match ! = txSeqBuf . end ( ) ) {
2021-02-22 22:25:09 +00:00
// Found matching entry?
// Send "untracked" as it has already been sent once.
2021-02-23 20:48:53 +00:00
// Don't constantly retransmit the same packet, give-up eventually
2021-02-25 11:13:18 +00:00
//qDebug(logUdp()) << this->metaObject()->className() << ": Sending retransmit of " << hex << match->seqNum;
2021-02-24 22:56:40 +00:00
match - > retransmitCount + + ;
2021-03-03 09:50:15 +00:00
QMutexLocker udplocker ( & udpMutex ) ;
2021-02-24 22:56:40 +00:00
udp - > writeDatagram ( match - > data , radioIP , port ) ;
2021-02-20 18:29:23 +00:00
}
2021-02-04 18:52:00 +00:00
}
2021-02-24 22:56:40 +00:00
if ( in - > type = = 0x04 ) {
2021-03-09 17:22:16 +00:00
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Received I am here " ;
2021-02-24 22:56:40 +00:00
areYouThereCounter = 0 ;
// I don't think that we will ever receive an "I am here" other than in response to "Are you there?"
remoteId = in - > sentid ;
2021-02-25 11:13:18 +00:00
if ( areYouThereTimer ! = Q_NULLPTR & & areYouThereTimer - > isActive ( ) ) {
// send ping packets every second
areYouThereTimer - > stop ( ) ;
}
2021-02-24 22:56:40 +00:00
sendControl ( false , 0x06 , 0x01 ) ; // Send Are you ready - untracked.
}
else if ( in - > type = = 0x06 )
{
// Just get the seqnum and ignore the rest.
}
2021-02-20 20:27:35 +00:00
break ;
2021-02-04 18:52:00 +00:00
}
2021-02-20 18:29:23 +00:00
case ( PING_SIZE ) : // ping packet
2021-02-04 18:52:00 +00:00
{
2021-02-20 18:29:23 +00:00
ping_packet_t in = ( ping_packet_t ) r . constData ( ) ;
if ( in - > type = = 0x07 )
2021-02-04 18:52:00 +00:00
{
2021-02-20 18:29:23 +00:00
// It is a ping request/response
if ( in - > reply = = 0x00 )
{
ping_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
p . len = sizeof ( p ) ;
p . type = 0x07 ;
p . sentid = myId ;
p . rcvdid = remoteId ;
p . reply = 0x01 ;
p . seq = in - > seq ;
p . time = in - > time ;
2021-03-03 09:50:15 +00:00
QMutexLocker udplocker ( & udpMutex ) ;
2021-02-20 18:29:23 +00:00
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , radioIP , port ) ;
}
2021-02-22 22:25:09 +00:00
else if ( in - > reply = = 0x01 ) {
2021-02-20 18:29:23 +00:00
if ( in - > seq = = pingSendSeq )
{
// This is response to OUR request so increment counter
pingSendSeq + + ;
}
else {
2021-02-22 22:25:09 +00:00
// Not sure what to do here, need to spend more time with the protocol but will try sending ping with same seq next time.
2021-02-24 22:56:40 +00:00
//qDebug(logUdp()) << this->metaObject()->className() << "Received out-of-sequence ping response. Sent:" << pingSendSeq << " received " << in->seq;
2021-02-20 18:29:23 +00:00
}
2021-02-13 23:25:24 +00:00
}
else {
2021-02-24 22:56:40 +00:00
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " Unhandled response to ping. I have never seen this! 0x10= " < < r [ 16 ] ;
2021-02-13 23:25:24 +00:00
}
2021-02-20 18:29:23 +00:00
2021-02-15 19:28:17 +00:00
}
2021-02-20 18:29:23 +00:00
break ;
}
default :
2021-02-22 22:25:09 +00:00
{
// All packets "should" be added to the incoming buffer.
// First check that we haven't already received it.
}
break ;
2021-02-04 18:52:00 +00:00
}
2021-02-22 22:25:09 +00:00
// All packets except ping and retransmit requests should trigger this.
control_packet_t in = ( control_packet_t ) r . constData ( ) ;
2021-02-24 22:56:40 +00:00
// This is a variable length retransmit request!
if ( in - > type = = 0x01 & & in - > len ! = 0x10 )
{
2021-03-03 09:50:15 +00:00
QMutexLocker txlocker ( & txBufferMutex ) ;
2021-02-24 22:56:40 +00:00
for ( quint16 i = 0x10 ; i < r . length ( ) ; i = i + 2 )
{
quint16 seq = ( quint8 ) r [ i ] | ( quint8 ) r [ i + 1 ] < < 8 ;
auto match = std : : find_if ( txSeqBuf . begin ( ) , txSeqBuf . end ( ) , [ & cs = seq ] ( SEQBUFENTRY & s ) {
return s . seqNum = = cs ;
} ) ;
if ( match = = txSeqBuf . end ( ) ) {
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Requested packet " < < hex < < seq < < " not found " ;
// Just send idle packet.
sendControl ( false , 0 , match - > seqNum ) ;
}
else {
// Found matching entry?
// Send "untracked" as it has already been sent once.
2021-02-25 11:13:18 +00:00
//qDebug(logUdp()) << this->metaObject()->className() << ": Sending retransmit (range) of " << hex << match->seqNum;
2021-02-24 22:56:40 +00:00
match - > retransmitCount + + ;
2021-03-03 09:50:15 +00:00
QMutexLocker udplocker ( & udpMutex ) ;
2021-02-24 22:56:40 +00:00
udp - > writeDatagram ( match - > data , radioIP , port ) ;
match + + ;
packetsLost + + ;
}
}
2021-02-27 00:37:00 +00:00
}
else if ( in - > len ! = PING_SIZE & & in - > type = = 0x00 & & in - > seq ! = 0x00 )
2021-02-22 22:25:09 +00:00
{
2021-03-03 09:50:15 +00:00
QMutexLocker rxlocker ( & rxBufferMutex ) ;
2021-02-24 22:56:40 +00:00
if ( rxSeqBuf . isEmpty ( ) ) {
rxSeqBuf . append ( in - > seq ) ;
}
2021-02-27 00:37:00 +00:00
else
2021-02-22 22:25:09 +00:00
{
2021-02-25 17:53:01 +00:00
std : : sort ( rxSeqBuf . begin ( ) , rxSeqBuf . end ( ) ) ;
2021-02-24 22:56:40 +00:00
if ( in - > seq < rxSeqBuf . front ( ) )
{
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : ******* seq number may have rolled over ****** previous highest: " < < hex < < rxSeqBuf . back ( ) < < " current: " < < hex < < in - > seq ;
2021-02-22 22:25:09 +00:00
2021-02-24 22:56:40 +00:00
// Looks like it has rolled over so clear buffer and start again.
rxSeqBuf . clear ( ) ;
2021-02-27 00:37:00 +00:00
return ;
2021-02-24 22:56:40 +00:00
}
2021-02-22 22:25:09 +00:00
2021-02-24 22:56:40 +00:00
if ( ! rxSeqBuf . contains ( in - > seq ) )
{
2021-02-27 00:37:00 +00:00
// Add incoming packet to the received buffer and if it is in the missing buffer, remove it.
2021-02-24 22:56:40 +00:00
rxSeqBuf . append ( in - > seq ) ;
// Check whether this is one of our missing ones!
auto s = std : : find_if ( rxMissing . begin ( ) , rxMissing . end ( ) , [ & cs = in - > seq ] ( SEQBUFENTRY & s ) { return s . seqNum = = cs ; } ) ;
if ( s ! = rxMissing . end ( ) )
{
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Missing SEQ has been received! " < < hex < < in - > seq ;
s = rxMissing . erase ( s ) ;
}
}
2021-02-27 00:37:00 +00:00
}
}
}
2021-02-22 22:25:09 +00:00
2021-02-27 00:37:00 +00:00
void udpBase : : sendRetransmitRequest ( )
{
// Find all gaps in received packets and then send requests for them.
// This will run every 100ms so out-of-sequence packets will not trigger a retransmit request.
QByteArray missingSeqs ;
2021-03-03 09:50:15 +00:00
QMutexLocker rxlocker ( & rxBufferMutex ) ;
2021-02-27 00:37:00 +00:00
auto i = std : : adjacent_find ( rxSeqBuf . begin ( ) , rxSeqBuf . end ( ) , [ ] ( quint16 l , quint16 r ) { return l + 1 < r ; } ) ;
while ( i ! = rxSeqBuf . end ( ) )
{
if ( i + 1 ! = rxSeqBuf . end ( ) )
{
if ( * ( i + 1 ) - * i < 30 )
2021-02-22 22:25:09 +00:00
{
2021-02-27 00:37:00 +00:00
for ( quint16 j = * i + 1 ; j < * ( i + 1 ) ; j + + )
2021-02-24 22:56:40 +00:00
{
2021-02-27 00:37:00 +00:00
//qDebug(logUdp()) << this->metaObject()->className() << ": Found missing seq between " << *i << " : " << *(i + 1) << " (" << j << ")";
auto s = std : : find_if ( rxMissing . begin ( ) , rxMissing . end ( ) , [ & cs = j ] ( SEQBUFENTRY & s ) { return s . seqNum = = cs ; } ) ;
if ( s = = rxMissing . end ( ) )
2021-02-24 22:56:40 +00:00
{
2021-02-27 00:37:00 +00:00
// We haven't seen this missing packet before
//qDebug(logUdp()) << this->metaObject()->className() << ": Adding to missing buffer (len="<< rxMissing.length() << "): " << j;
SEQBUFENTRY b ;
b . seqNum = j ;
b . retransmitCount = 0 ;
b . timeSent = QTime : : currentTime ( ) ;
rxMissing . append ( b ) ;
packetsLost + + ;
}
else {
if ( s - > retransmitCount = = 4 )
2021-02-24 22:56:40 +00:00
{
2021-02-27 00:37:00 +00:00
// We have tried 4 times to request this packet, time to give up!
s = rxMissing . erase ( s ) ;
rxSeqBuf . append ( j ) ; // Final thing is to add to received buffer!
2021-02-24 22:56:40 +00:00
}
2021-02-27 00:37:00 +00:00
2021-02-24 22:56:40 +00:00
}
2021-02-24 11:00:23 +00:00
}
2021-02-22 22:25:09 +00:00
}
2021-02-27 00:37:00 +00:00
else {
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : Too many missing, flushing buffers " ;
rxSeqBuf . clear ( ) ;
missingSeqs . clear ( ) ;
break ;
}
}
i + + ;
}
2021-02-22 22:25:09 +00:00
2021-02-23 20:48:53 +00:00
2021-02-27 00:37:00 +00:00
for ( auto it = rxMissing . begin ( ) ; it ! = rxMissing . end ( ) ; + + it )
{
if ( it - > retransmitCount < 10 )
{
missingSeqs . append ( it - > seqNum & 0xff ) ;
missingSeqs . append ( it - > seqNum > > 8 & 0xff ) ;
missingSeqs . append ( it - > seqNum & 0xff ) ;
missingSeqs . append ( it - > seqNum > > 8 & 0xff ) ;
it - > retransmitCount + + ;
}
}
if ( missingSeqs . length ( ) ! = 0 )
{
control_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
p . type = 0x01 ;
p . seq = 0x0000 ;
p . sentid = myId ;
p . rcvdid = remoteId ;
if ( missingSeqs . length ( ) = = 4 ) // This is just a single missing packet so send using a control.
{
p . seq = ( missingSeqs [ 0 ] & 0xff ) | ( quint16 ) ( missingSeqs [ 1 ] < < 8 ) ;
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : sending request for missing packet : " < < hex < < p . seq ;
2021-03-03 09:50:15 +00:00
QMutexLocker udplocker ( & udpMutex ) ;
2021-02-27 00:37:00 +00:00
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , radioIP , port ) ;
}
else
{
qDebug ( logUdp ( ) ) < < this - > metaObject ( ) - > className ( ) < < " : sending request for multiple missing packets : " < < missingSeqs . toHex ( ) ;
missingSeqs . insert ( 0 , p . packet , sizeof ( p . packet ) ) ;
2021-03-03 09:50:15 +00:00
QMutexLocker udplocker ( & udpMutex ) ;
2021-02-27 00:37:00 +00:00
udp - > writeDatagram ( missingSeqs , radioIP , port ) ;
2021-02-22 22:25:09 +00:00
}
}
2021-02-27 00:37:00 +00:00
2021-02-04 18:52:00 +00:00
}
2021-02-27 00:37:00 +00:00
2021-02-18 15:54:26 +00:00
// Used to send idle and other "control" style messages
2021-02-20 18:29:23 +00:00
void udpBase : : sendControl ( bool tracked = true , quint8 type = 0 , quint16 seq = 0 )
2021-02-03 20:00:40 +00:00
{
2021-02-20 18:29:23 +00:00
control_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
p . len = sizeof ( p ) ;
p . type = type ;
p . sentid = myId ;
p . rcvdid = remoteId ;
2021-02-03 20:00:40 +00:00
2021-02-04 13:12:08 +00:00
if ( ! tracked ) {
2021-02-20 18:29:23 +00:00
p . seq = seq ;
2021-03-03 09:50:15 +00:00
QMutexLocker udplocker ( & udpMutex ) ;
2021-02-20 18:29:23 +00:00
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , radioIP , port ) ;
2021-02-04 13:12:08 +00:00
}
else {
2021-02-20 18:29:23 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ) ;
2021-02-04 13:12:08 +00:00
}
2021-02-03 20:00:40 +00:00
return ;
}
2021-02-13 23:25:24 +00:00
// Send periodic ping packets
void udpBase : : sendPing ( )
2021-02-03 20:00:40 +00:00
{
2021-02-20 18:29:23 +00:00
ping_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
p . len = sizeof ( p ) ;
p . type = 0x07 ;
p . sentid = myId ;
p . rcvdid = remoteId ;
p . seq = pingSendSeq ;
p . time = timeStarted . msecsSinceStartOfDay ( ) ;
2021-02-13 23:25:24 +00:00
lastPingSentTime = QDateTime : : currentDateTime ( ) ;
2021-03-03 09:50:15 +00:00
QMutexLocker udplocker ( & udpMutex ) ;
2021-02-20 18:29:23 +00:00
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , radioIP , port ) ;
2021-02-22 22:25:09 +00:00
return ;
}
2021-02-24 11:00:23 +00:00
void udpBase : : sendRetransmitRange ( quint16 first , quint16 second , quint16 third , quint16 fourth )
2021-02-22 22:25:09 +00:00
{
retransmit_range_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
p . len = sizeof ( p ) ;
p . type = 0x00 ;
p . sentid = myId ;
p . rcvdid = remoteId ;
p . first = first ;
2021-02-24 11:00:23 +00:00
p . second = second ;
p . third = third ;
p . fourth = fourth ;
2021-03-03 09:50:15 +00:00
QMutexLocker udplocker ( & udpMutex ) ;
2021-02-22 22:25:09 +00:00
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , radioIP , port ) ;
2021-02-03 20:00:40 +00:00
return ;
}
2021-02-13 23:25:24 +00:00
void udpBase : : sendTrackedPacket ( QByteArray d )
2021-02-03 20:00:40 +00:00
{
// As the radio can request retransmission of these packets, store them in a buffer (eventually!)
d [ 6 ] = sendSeq & 0xff ;
d [ 7 ] = ( sendSeq > > 8 ) & 0xff ;
2021-02-04 13:12:08 +00:00
SEQBUFENTRY s ;
s . seqNum = sendSeq ;
2021-02-24 22:56:40 +00:00
s . timeSent = QTime : : currentTime ( ) ;
2021-02-24 11:00:23 +00:00
s . retransmitCount = 0 ;
2021-02-24 22:56:40 +00:00
s . data = d ;
2021-03-03 09:50:15 +00:00
QMutexLocker txlocker ( & txBufferMutex ) ;
2021-02-04 13:12:08 +00:00
txSeqBuf . append ( s ) ;
2021-03-03 09:50:15 +00:00
QMutexLocker rxlocker ( & rxBufferMutex ) ;
2021-02-13 23:25:24 +00:00
purgeOldEntries ( ) ; // Delete entries older than PURGE_SECONDS seconds (currently 5)
2021-02-03 20:00:40 +00:00
sendSeq + + ;
2021-03-03 09:50:15 +00:00
QMutexLocker udplocker ( & udpMutex ) ;
2021-02-13 23:25:24 +00:00
udp - > writeDatagram ( d , radioIP , port ) ;
2021-02-21 14:53:42 +00:00
if ( idleTimer ! = Q_NULLPTR & & idleTimer - > isActive ( ) ) {
idleTimer - > start ( IDLE_PERIOD ) ; // Reset idle counter if it's running
2021-02-13 23:25:24 +00:00
}
2021-02-14 10:40:47 +00:00
packetsSent + + ;
2021-02-13 23:25:24 +00:00
return ;
2021-02-03 20:00:40 +00:00
}
2021-02-24 22:56:40 +00:00
/// <summary>
/// Once a packet has reached PURGE_SECONDS old (currently 10) then it is not likely to be any use.
/// </summary>
2021-02-13 23:25:24 +00:00
void udpBase : : purgeOldEntries ( )
2021-02-03 20:00:40 +00:00
{
2021-02-24 22:56:40 +00:00
// Erase old entries from the tx packet buffer
2021-02-26 16:53:11 +00:00
if ( ! txSeqBuf . isEmpty ( ) )
{
txSeqBuf . erase ( std : : remove_if ( txSeqBuf . begin ( ) , txSeqBuf . end ( ) , [ ] ( const SEQBUFENTRY & v )
{ return v . timeSent . secsTo ( QTime : : currentTime ( ) ) > PURGE_SECONDS ; } ) , txSeqBuf . end ( ) ) ;
}
2021-02-23 20:48:53 +00:00
2021-02-24 22:56:40 +00:00
// Erase old entries from the missing packets buffer
2021-02-26 16:53:11 +00:00
if ( ! rxMissing . isEmpty ( ) ) {
rxMissing . erase ( std : : remove_if ( rxMissing . begin ( ) , rxMissing . end ( ) , [ ] ( const SEQBUFENTRY & v )
{ return v . timeSent . secsTo ( QTime : : currentTime ( ) ) > PURGE_SECONDS ; } ) , rxMissing . end ( ) ) ;
}
2021-02-24 22:56:40 +00:00
2021-02-26 16:53:11 +00:00
if ( ! rxSeqBuf . isEmpty ( ) ) {
std : : sort ( rxSeqBuf . begin ( ) , rxSeqBuf . end ( ) ) ;
2021-02-25 17:53:01 +00:00
2021-02-26 16:53:11 +00:00
if ( rxSeqBuf . length ( ) > 400 )
{
rxSeqBuf . remove ( 0 , 200 ) ;
}
2021-02-22 22:25:09 +00:00
}
2021-02-03 20:00:40 +00:00
}
2021-02-13 23:25:24 +00:00
/// <summary>
/// passcode function used to generate secure (ish) code
/// </summary>
/// <param name="str"></param>
/// <returns>pointer to encoded username or password</returns>
2021-02-15 19:28:17 +00:00
void passcode ( QString in , QByteArray & out )
2021-02-03 20:00:40 +00:00
{
2021-02-09 12:43:28 +00:00
const quint8 sequence [ ] =
2021-02-03 20:00:40 +00:00
{
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0x47 , 0x5d , 0x4c , 0x42 , 0x66 , 0x20 , 0x23 , 0x46 , 0x4e , 0x57 , 0x45 , 0x3d , 0x67 , 0x76 , 0x60 , 0x41 , 0x62 , 0x39 , 0x59 , 0x2d , 0x68 , 0x7e ,
0x7c , 0x65 , 0x7d , 0x49 , 0x29 , 0x72 , 0x73 , 0x78 , 0x21 , 0x6e , 0x5a , 0x5e , 0x4a , 0x3e , 0x71 , 0x2c , 0x2a , 0x54 , 0x3c , 0x3a , 0x63 , 0x4f ,
0x43 , 0x75 , 0x27 , 0x79 , 0x5b , 0x35 , 0x70 , 0x48 , 0x6b , 0x56 , 0x6f , 0x34 , 0x32 , 0x6c , 0x30 , 0x61 , 0x6d , 0x7b , 0x2f , 0x4b , 0x64 , 0x38 ,
0x2b , 0x2e , 0x50 , 0x40 , 0x3f , 0x55 , 0x33 , 0x37 , 0x25 , 0x77 , 0x24 , 0x26 , 0x74 , 0x6a , 0x28 , 0x53 , 0x4d , 0x69 , 0x22 , 0x5c , 0x44 , 0x31 ,
0x36 , 0x58 , 0x3b , 0x7a , 0x51 , 0x5f , 0x52 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
} ;
2021-02-15 19:28:17 +00:00
QByteArray ba = in . toLocal8Bit ( ) ;
2021-02-03 20:00:40 +00:00
uchar * ascii = ( uchar * ) ba . constData ( ) ;
2021-02-15 19:28:17 +00:00
for ( int i = 0 ; i < in . length ( ) & & i < 16 ; i + + )
2021-02-03 20:00:40 +00:00
{
int p = ascii [ i ] + i ;
2021-02-05 17:40:58 +00:00
if ( p > 126 )
{
2021-02-03 20:00:40 +00:00
p = 32 + p % 127 ;
2021-02-05 17:40:58 +00:00
}
2021-02-15 19:28:17 +00:00
out . append ( sequence [ p ] ) ;
2021-02-03 20:00:40 +00:00
}
2021-02-15 19:28:17 +00:00
return ;
2021-02-03 20:00:40 +00:00
}
2021-02-13 23:25:24 +00:00
/// <summary>
/// returns a QByteArray of a null terminated string
/// </summary>
/// <param name="c"></param>
/// <param name="s"></param>
/// <returns></returns>
QByteArray parseNullTerminatedString ( QByteArray c , int s )
2021-02-03 20:00:40 +00:00
{
2021-02-07 17:40:38 +00:00
//QString res = "";
QByteArray res ;
2021-02-03 20:00:40 +00:00
for ( int i = s ; i < c . length ( ) ; i + + )
{
if ( c [ i ] ! = ' \0 ' )
2021-02-05 17:40:58 +00:00
{
2021-02-07 17:40:38 +00:00
res . append ( c [ i ] ) ;
2021-02-05 17:40:58 +00:00
}
2021-02-03 20:00:40 +00:00
else
2021-02-05 17:40:58 +00:00
{
2021-02-03 20:00:40 +00:00
break ;
2021-02-05 17:40:58 +00:00
}
2021-02-03 20:00:40 +00:00
}
return res ;
2021-02-04 06:00:13 +00:00
}
2021-02-14 18:32:58 +00:00