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-13 23:25:24 +00:00
udpHandler : : udpHandler ( QString ip , quint16 controlPort , quint16 civPort , quint16 audioPort , QString username , QString password ,
quint16 buffer , quint16 rxsample , quint8 rxcodec , quint16 txsample , quint8 txcodec ) :
controlPort ( controlPort ) ,
civPort ( civPort ) ,
audioPort ( audioPort )
2021-02-03 20:00:40 +00:00
{
2021-02-07 18:46:47 +00:00
2021-02-13 23:25:24 +00:00
this - > port = this - > controlPort ;
2021-02-03 20:00:40 +00:00
this - > username = username ;
this - > password = password ;
2021-02-09 12:43:28 +00:00
this - > rxBufferSize = buffer ;
this - > rxSampleRate = rxsample ;
this - > txSampleRate = txsample ;
this - > rxCodec = rxcodec ;
this - > txCodec = txcodec ;
2021-02-13 23:25:24 +00:00
qDebug ( ) < < " Starting udpHandler user: " < < username < < " buffer: " < < buffer < < " rx sample rate: " < < rxsample < <
" rx codec: " < < rxcodec < < " tx sample rate: " < < txsample < < " 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.
if ( ! radioIP . setAddress ( ip ) )
{
QHostInfo remote = QHostInfo : : fromName ( ip ) ;
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 ;
qDebug ( ) < < " Got IP Address : " < < ip < < " : " < < addr . toString ( ) ;
break ;
}
2021-02-07 18:46:47 +00:00
}
2021-02-07 19:09:19 +00:00
if ( radioIP . isNull ( ) )
{
qDebug ( ) < < " Error obtaining IP Address for : " < < ip < < " : " < < 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-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
*/
connect ( & tokenTimer , & QTimer : : timeout , this , std : : bind ( & udpHandler : : sendToken , this , 0x05 ) ) ;
2021-02-14 07:53:55 +00:00
connect ( & areYouThereTimer , & QTimer : : timeout , this , QOverload < > : : of ( & udpHandler : : sendAreYouThere ) ) ;
2021-02-13 23:25:24 +00:00
connect ( & pingTimer , & QTimer : : timeout , this , & udpBase : : sendPing ) ;
connect ( & idleTimer , & QTimer : : timeout , this , std : : bind ( & udpBase : : sendIdle , this , true , 0 ) ) ;
2021-02-04 19:53:48 +00:00
2021-02-13 23:25:24 +00:00
// Start sending are you there packets - will be stopped once "I am here" received
2021-02-14 07:53:55 +00:00
areYouThereTimer . start ( AREYOUTHERE_PERIOD ) ;
2021-02-03 20:00:40 +00:00
2021-02-13 23:25:24 +00:00
// Set my computer name. Should this be configurable?
2021-02-07 17:40:38 +00:00
compName = QString ( " wfview " ) . toUtf8 ( ) ;
2021-02-13 23:25:24 +00:00
2021-02-03 20:00:40 +00:00
}
udpHandler : : ~ udpHandler ( )
{
2021-02-13 23:25:24 +00:00
if ( isAuthenticated ) {
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-03 20:00:40 +00:00
2021-02-13 23:25:24 +00:00
qDebug ( ) < < " Sending token removal packet " ;
sendToken ( 0x01 ) ;
2021-02-03 20:00:40 +00:00
}
}
2021-02-08 16:53:26 +00:00
void udpHandler : : changeBufferSize ( quint16 value )
{
emit haveChangeBufferSize ( value ) ;
}
2021-02-13 23:25:24 +00:00
void udpHandler : : receiveFromCivStream ( QByteArray data )
2021-02-03 20:00:40 +00:00
{
emit haveDataFromPort ( data ) ;
}
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 ( ) ) {
lastReceived = time ( 0 ) ;
QNetworkDatagram datagram = udp - > receiveDatagram ( ) ;
//qDebug() << "Received: " << datagram.data();
QByteArray r = datagram . data ( ) ;
switch ( r . length ( ) )
{
2021-02-13 23:25:24 +00:00
case ( 16 ) :
if ( r . mid ( 0 , 8 ) = = QByteArrayLiteral ( " \x10 \x00 \x00 \x00 \x04 \x00 \x00 \x00 " ) ) {
// If timer is active, stop it as they are obviously there!
if ( areYouThereTimer . isActive ( ) ) {
areYouThereTimer . stop ( ) ;
// send ping packets every second
2021-02-14 07:53:55 +00:00
pingTimer . start ( PING_PERIOD ) ;
idleTimer . start ( IDLE_PERIOD ) ;
2021-02-03 20:00:40 +00:00
}
}
2021-02-13 23:25:24 +00:00
// This is "I am ready" in response to "Are you ready" so send login.
else if ( r . mid ( 0 , 8 ) = = QByteArrayLiteral ( " \x10 \x00 \x00 \x00 \x06 \x00 \x01 \x00 " ) )
{
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Received I am ready " ;
remoteId = qFromBigEndian < quint32 > ( r . mid ( 8 , 4 ) ) ;
sendLogin ( ) ; // second login packet
}
2021-02-03 20:00:40 +00:00
break ;
2021-02-05 21:23:00 +00:00
case ( 21 ) : // pkt7,
2021-02-06 10:54:20 +00:00
if ( r . mid ( 1 , 5 ) = = QByteArrayLiteral ( " \x00 \x00 \x00 \x07 \x00 " ) & & r [ 16 ] = = ( char ) 0x01 & & serialAndAudioOpened )
2021-02-05 21:23:00 +00:00
{
2021-02-14 15:30:34 +00:00
// This is a response to our ping request so measure latency
2021-02-13 23:25:24 +00:00
latency + = lastPingSentTime . msecsTo ( QDateTime : : currentDateTime ( ) ) ;
2021-02-05 21:23:00 +00:00
latency / = 2 ;
2021-02-14 10:40:47 +00:00
quint32 totalsent = packetsSent ;
2021-02-14 16:14:56 +00:00
quint32 totallost = packetsLost / 2 ;
2021-02-14 10:40:47 +00:00
if ( audio ! = Q_NULLPTR ) {
totalsent = totalsent + audio - > packetsSent ;
2021-02-14 16:14:56 +00:00
totallost = totallost + audio - > packetsLost / 2 ;
2021-02-14 10:40:47 +00:00
}
if ( civ ! = Q_NULLPTR ) {
totalsent = totalsent + civ - > packetsSent ;
2021-02-14 16:14:56 +00:00
totallost = totallost + civ - > packetsLost / 2 ;
2021-02-14 10:40:47 +00:00
}
2021-02-14 16:14:56 +00:00
//double perclost = 1.0 * totallost / totalsent * 100.0 ;
2021-02-14 10:40:47 +00:00
2021-02-14 16:14:56 +00:00
emit haveNetworkStatus ( " rtt: " + QString : : number ( latency ) + " ms, loss: ( " + QString : : number ( packetsLost ) + " / " + QString : : number ( packetsSent ) + " ) " ) ;
2021-02-05 21:23:00 +00:00
}
break ;
2021-02-03 20:00:40 +00:00
case ( 64 ) : // Response to Auth packet?
2021-02-14 07:15:49 +00:00
if ( r . mid ( 0 , 6 ) = = QByteArrayLiteral ( " \x40 \x00 \x00 \x00 \x00 \x00 " ) & & r [ 21 ] = = ( char ) 0x05 ) {
if ( r . mid ( 0x30 , 4 ) = = QByteArrayLiteral ( " \x00 \x00 \x00 \x00 " ) ) {
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Token renewal successful " ;
2021-02-14 16:14:56 +00:00
tokenTimer . start ( TOKEN_RENEWAL ) ;
2021-02-03 20:00:40 +00:00
gotAuthOK = true ;
if ( ! serialAndAudioOpened )
2021-02-05 17:40:58 +00:00
{
2021-02-13 23:25:24 +00:00
sendRequestSerialAndAudio ( ) ;
2021-02-05 17:40:58 +00:00
}
2021-02-14 07:15:49 +00:00
}
else if ( r . mid ( 0x30 , 4 ) = = QByteArrayLiteral ( " \xff \xff \xff \xff " ) )
{
qWarning ( ) < < this - > metaObject ( ) - > className ( ) < < " : Radio rejected token renewal, performing login " ;
remoteId = qFromBigEndian < quint32 > ( r . mid ( 8 , 4 ) ) ;
isAuthenticated = false ;
2021-02-14 15:30:34 +00:00
sendLogin ( ) ; // Try sending login packet (didn't seem to work?)
2021-02-14 07:15:49 +00:00
}
else
{
qWarning ( ) < < this - > metaObject ( ) - > className ( ) < < " : Unknown response to token renewal? " < < r . mid ( 0x30 , 4 ) ;
2021-02-03 20:00:40 +00:00
}
}
break ;
case ( 80 ) : // Status packet
if ( r . mid ( 0 , 6 ) = = QByteArrayLiteral ( " \x50 \x00 \x00 \x00 \x00 \x00 " ) )
{
if ( r . mid ( 48 , 3 ) = = QByteArrayLiteral ( " \xff \xff \xff " ) )
2021-02-05 17:40:58 +00:00
{
2021-02-07 17:40:38 +00:00
if ( ! serialAndAudioOpened )
2021-02-05 17:40:58 +00:00
{
2021-02-04 19:53:48 +00:00
emit haveNetworkError ( radioIP . toString ( ) , " Auth failed, try rebooting the radio. " ) ;
2021-02-14 07:15:49 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Auth failed, try rebooting the radio. " ;
2021-02-03 20:00:40 +00:00
}
2021-02-05 17:40:58 +00:00
}
2021-02-07 17:40:38 +00:00
if ( r . mid ( 48 , 3 ) = = QByteArrayLiteral ( " \x00 \x00 \x00 " ) & & r [ 64 ] = = ( char ) 0x01 )
2021-02-05 17:40:58 +00:00
{
2021-02-04 19:53:48 +00:00
emit haveNetworkError ( radioIP . toString ( ) , " Got radio disconnected. " ) ;
2021-02-14 07:15:49 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Got radio disconnected. " ;
2021-02-03 20:00:40 +00:00
}
}
break ;
case ( 96 ) : // Response to Login packet.
if ( r . mid ( 0 , 6 ) = = QByteArrayLiteral ( " \x60 \x00 \x00 \x00 \x00 \x00 " ) )
{
if ( r . mid ( 48 , 4 ) = = QByteArrayLiteral ( " \xff \xff \xff \xfe " ) )
{
2021-02-13 23:25:24 +00:00
emit haveNetworkStatus ( " Invalid Username/Password " ) ;
2021-02-14 07:15:49 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Invalid Username/Password " ;
2021-02-03 20:00:40 +00:00
}
else if ( ! isAuthenticated )
{
2021-02-13 23:25:24 +00:00
emit haveNetworkStatus ( " Radio Login OK! " ) ;
2021-02-14 07:15:49 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Received Login OK " ;
2021-02-03 20:00:40 +00:00
2021-02-14 15:30:34 +00:00
authId = r . mid ( 0x1a , 6 ) ;
2021-02-13 23:25:24 +00:00
sendToken ( 0x02 ) ;
2021-02-14 07:53:55 +00:00
tokenTimer . start ( TOKEN_RENEWAL ) ; // Start token request timer
2021-02-03 20:00:40 +00:00
isAuthenticated = true ;
}
2021-02-14 07:53:55 +00:00
if ( r . mid ( 0x40 , 4 ) = = QByteArrayLiteral ( " FTTH " ) )
{
highBandwidthConnection = true ;
}
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Detected connection speed " < < QString : : fromUtf8 ( parseNullTerminatedString ( r , 0x40 ) ) ;
2021-02-03 20:00:40 +00:00
}
break ;
case ( 144 ) :
2021-02-13 23:25:24 +00:00
if ( ! serialAndAudioOpened & & r . mid ( 0 , 6 ) = = QByteArrayLiteral ( " \x90 \x00 \x00 \x00 \x00 \x00 " ) & & r [ 0x60 ] = = ( char ) 0x00 )
2021-02-05 17:40:58 +00:00
{
2021-02-09 13:57:03 +00:00
devName = parseNullTerminatedString ( r , 0x40 ) ;
2021-02-07 18:13:22 +00:00
QHostAddress ip = QHostAddress ( qFromBigEndian < quint32 > ( r . mid ( 0x84 , 4 ) ) ) ;
2021-02-12 14:46:02 +00:00
if ( ! ip . isEqual ( QHostAddress ( " 0.0.0.0 " ) ) & & parseNullTerminatedString ( r , 0x64 ) ! = compName ) // || ip != localIP ) // TODO: More testing of IP address detection code!
2021-02-07 17:40:38 +00:00
{
2021-02-13 23:25:24 +00:00
emit haveNetworkStatus ( QString : : fromUtf8 ( devName ) + " in use by: " + QString : : fromUtf8 ( parseNullTerminatedString ( r , 0x64 ) ) + " ( " + ip . toString ( ) + " ) " ) ;
}
else {
emit haveNetworkStatus ( QString : : fromUtf8 ( devName ) + " available " ) ;
sendRequestSerialAndAudio ( ) ;
}
}
else if ( ! serialAndAudioOpened & & r . mid ( 0 , 6 ) = = QByteArrayLiteral ( " \x90 \x00 \x00 \x00 \x00 \x00 " ) & & r [ 0x60 ] = = ( char ) 0x01 )
{
devName = parseNullTerminatedString ( r , 0x40 ) ;
2021-02-05 20:26:18 +00:00
2021-02-13 23:25:24 +00:00
civ = new udpCivData ( localIP , radioIP , civPort ) ;
audio = new udpAudio ( localIP , radioIP , audioPort , rxBufferSize , rxSampleRate , rxCodec , txSampleRate , txCodec ) ;
2021-02-03 20:00:40 +00:00
2021-02-13 23:25:24 +00:00
QObject : : connect ( civ , SIGNAL ( receive ( QByteArray ) ) , this , SLOT ( receiveFromCivStream ( QByteArray ) ) ) ;
2021-02-08 16:53:26 +00:00
QObject : : connect ( this , SIGNAL ( haveChangeBufferSize ( quint16 ) ) , audio , SLOT ( changeBufferSize ( quint16 ) ) ) ;
2021-02-07 17:40:38 +00:00
serialAndAudioOpened = true ;
2021-02-03 20:00:40 +00:00
2021-02-07 17:40:38 +00:00
emit haveNetworkStatus ( QString : : fromUtf8 ( devName ) ) ;
2021-02-03 20:00:40 +00:00
2021-02-13 23:25:24 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " Got serial and audio request success, device name: " < < QString : : fromUtf8 ( devName ) ;
2021-02-03 20:00:40 +00:00
2021-02-07 17:40:38 +00:00
// Stuff can change in the meantime because of a previous login...
2021-02-14 15:30:34 +00:00
remoteId = qFromBigEndian < quint32 > ( r . mid ( 0x08 , 4 ) ) ;
myId = qFromBigEndian < quint32 > ( r . mid ( 0x0c , 4 ) ) ;
authId = r . mid ( 0x1a , 6 ) ;
// Is there already somebody connected to the radio?
2021-02-03 20:00:40 +00:00
}
break ;
case ( 168 ) :
2021-02-14 15:30:34 +00:00
audioType = parseNullTerminatedString ( r , 0x72 ) ;
devName = parseNullTerminatedString ( r , 0x52 ) ;
replyId = r . mid ( 0x42 , 16 ) ;
2021-02-13 23:25:24 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " Received radio capabilities, Name: " < <
2021-02-14 15:30:34 +00:00
QString : : fromUtf8 ( devName ) < < " Audio: " < <
QString : : fromUtf8 ( audioType ) ;
2021-02-03 20:00:40 +00:00
break ;
}
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-13 23:25:24 +00:00
void udpHandler : : sendRequestSerialAndAudio ( )
2021-02-03 20:00:40 +00:00
{
2021-02-13 23:25:24 +00:00
quint8 * usernameEncoded = passcode ( username ) ;
2021-02-11 19:18:35 +00:00
int txSeqBufLengthMs = 50 ;
2021-02-11 19:47:29 +00:00
2021-02-14 15:30:34 +00:00
quint8 p [ ] = {
2021-02-03 20:00:40 +00:00
0x90 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff ) ,
2021-02-14 15:30:34 +00:00
0x00 , 0x00 , 0x00 , 0x80 , 0x01 , 0x03 , 0x00 , static_cast < quint8 > ( authInnerSendSeq & 0xff ) , static_cast < quint8 > ( authInnerSendSeq > > 8 & 0xff ) , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-03 20:00:40 +00:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-09 12:43:28 +00:00
0x01 , 0x01 , rxCodec , txCodec , 0x00 , 0x00 , static_cast < quint8 > ( rxSampleRate > > 8 & 0xff ) , static_cast < quint8 > ( rxSampleRate & 0xff ) ,
0x00 , 0x00 , static_cast < quint8 > ( txSampleRate > > 8 & 0xff ) , static_cast < quint8 > ( txSampleRate & 0xff ) ,
2021-02-13 23:25:24 +00:00
0x00 , 0x00 , static_cast < quint8 > ( civPort > > 8 & 0xff ) , static_cast < quint8 > ( civPort & 0xff ) ,
0x00 , 0x00 , static_cast < quint8 > ( audioPort > > 8 & 0xff ) , static_cast < quint8 > ( audioPort & 0xff ) , 0x00 , 0x00 ,
2021-02-09 12:43:28 +00:00
static_cast < quint8 > ( txSeqBufLengthMs > > 8 & 0xff ) , static_cast < quint8 > ( txSeqBufLengthMs & 0xff ) , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
2021-02-03 20:00:40 +00:00
} ;
2021-02-14 15:30:34 +00:00
memcpy ( p + 0x1a , authId . constData ( ) , authId . length ( ) ) ;
memcpy ( p + 0x20 , replyId . constData ( ) , replyId . length ( ) ) ;
memcpy ( p + 0x40 , devName . constData ( ) , devName . length ( ) ) ;
memcpy ( p + 0x60 , usernameEncoded , strlen ( ( const char * ) usernameEncoded ) ) ;
2021-02-03 20:00:40 +00:00
authInnerSendSeq + + ;
delete [ ] usernameEncoded ;
2021-02-13 23:25:24 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) ) ;
return ;
2021-02-03 20:00:40 +00:00
}
2021-02-14 07:53:55 +00:00
void udpHandler : : sendAreYouThere ( )
{
if ( areYouThereCounter = = 20 )
{
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Radio not responding. " ;
emit haveNetworkStatus ( " Radio not responding! " ) ;
}
areYouThereCounter + + ;
udpBase : : sendAreYouThere ( ) ;
}
2021-02-03 20:00:40 +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-13 23:25:24 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Sending login packet " ;
2021-02-03 20:00:40 +00:00
uint16_t authStartID = rand ( ) | rand ( ) < < 8 ;
2021-02-13 23:25:24 +00:00
quint8 * usernameEncoded = passcode ( username ) ;
quint8 * passwordEncoded = passcode ( password ) ;
2021-02-03 20:00:40 +00:00
2021-02-09 12:43:28 +00:00
quint8 p [ ] = {
2021-02-03 20:00:40 +00:00
0x80 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff ) ,
2021-02-09 12:43:28 +00:00
0x00 , 0x00 , 0x00 , 0x70 , 0x01 , 0x00 , 0x00 , static_cast < quint8 > ( authInnerSendSeq & 0xff ) , static_cast < quint8 > ( authInnerSendSeq > > 8 & 0xff ) ,
0x00 , static_cast < quint8 > ( authStartID & 0xff ) , static_cast < quint8 > ( authStartID > > 8 & 0xff ) , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-03 20:00:40 +00:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-14 15:30:34 +00:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-07 17:40:38 +00:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-03 20:00:40 +00:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
2021-02-07 17:40:38 +00:00
2021-02-14 15:30:34 +00:00
memcpy ( p + 0x40 , usernameEncoded , strlen ( ( const char * ) usernameEncoded ) ) ;
memcpy ( p + 0x50 , passwordEncoded , strlen ( ( const char * ) passwordEncoded ) ) ;
2021-02-07 17:40:38 +00:00
memcpy ( p + 0x60 , compName . constData ( ) , compName . length ( ) ) ;
2021-02-03 20:00:40 +00:00
delete [ ] usernameEncoded ;
delete [ ] passwordEncoded ;
authInnerSendSeq + + ;
2021-02-13 23:25:24 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) ) ;
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-14 16:23:25 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " Sending Token request: " < < magic ;
2021-02-14 15:30:34 +00:00
quint8 p [ ] = {
2021-02-03 20:00:40 +00:00
0x40 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff ) ,
2021-02-09 12:43:28 +00:00
0x00 , 0x00 , 0x00 , 0x30 , 0x01 , static_cast < quint8 > ( magic ) , 0x00 , static_cast < quint8 > ( authInnerSendSeq & 0xff ) , static_cast < quint8 > ( ( authInnerSendSeq ) > > 8 & 0xff ) , 0x00 ,
2021-02-14 15:30:34 +00:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-03 20:00:40 +00:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
2021-02-14 15:30:34 +00:00
memcpy ( p + 0x1a , authId . constData ( ) , authId . length ( ) ) ;
2021-02-03 20:00:40 +00:00
authInnerSendSeq + + ;
2021-02-13 23:25:24 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) ) ;
2021-02-14 16:14:56 +00:00
tokenTimer . start ( 100 ) ; // Set 100ms timer for retry.
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-13 23:25:24 +00:00
qDebug ( ) < < " 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-13 23:25:24 +00:00
sendAreYouThere ( ) ; // First connect packet
/*
Connect various timers
*/
connect ( & pingTimer , & QTimer : : timeout , this , & udpBase : : sendPing ) ;
connect ( & idleTimer , & QTimer : : timeout , this , std : : bind ( & udpBase : : sendIdle , this , true , 0 ) ) ;
// send ping packets every 100 ms (maybe change to less frequent?)
2021-02-14 07:53:55 +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-14 07:53:55 +00:00
idleTimer . start ( IDLE_PERIOD ) ;
2021-02-03 20:00:40 +00:00
}
2021-02-13 23:25:24 +00:00
udpCivData : : ~ udpCivData ( ) {
sendOpenClose ( true ) ;
}
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
{
// qDebug() << "Sending: (" << d.length() << ") " << d;
uint16_t l = d . length ( ) ;
2021-02-09 12:43:28 +00:00
const quint8 p [ ] = { static_cast < quint8 > ( 0x15 + l ) , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff ) ,
2021-02-09 12:43:28 +00:00
0xc1 , static_cast < quint8 > ( l ) , 0x00 , static_cast < quint8 > ( sendSeqB > > 8 & 0xff ) , static_cast < quint8 > ( sendSeqB & 0xff )
2021-02-03 20:00:40 +00:00
} ;
QByteArray t = QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) ;
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 : : SendIdle ( )
2021-02-03 20:00:40 +00:00
{
2021-02-09 12:43:28 +00:00
const quint8 p [ ] = { 0x10 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff )
2021-02-03 20:00:40 +00:00
} ;
2021-02-13 23:25:24 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) ) ;
2021-02-03 20:00:40 +00:00
}
2021-02-13 23:25:24 +00:00
void udpCivData : : SendPeriodic ( )
2021-02-03 20:00:40 +00:00
{
2021-02-09 12:43:28 +00:00
const quint8 p [ ] = { 0x15 , 0x00 , 0x07 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff )
2021-02-03 20:00:40 +00:00
} ;
2021-02-13 23:25:24 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) ) ;
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
{
uint8_t magic = 0x05 ;
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-09 12:43:28 +00:00
const quint8 p [ ] = {
2021-02-03 20:00:40 +00:00
0x16 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff ) ,
2021-02-12 14:31:26 +00:00
0xc0 , 0x01 , 0x00 , static_cast < quint8 > ( sendSeqB > > 8 & 0xff ) , static_cast < quint8 > ( sendSeqB & 0xff ) , static_cast < quint8 > ( magic )
2021-02-03 20:00:40 +00:00
} ;
sendSeqB + + ;
2021-02-13 23:25:24 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) ) ;
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
{
while ( udp - > hasPendingDatagrams ( ) ) {
QNetworkDatagram datagram = udp - > receiveDatagram ( ) ;
//qDebug() << "Received: " << datagram.data();
QByteArray r = datagram . data ( ) ;
switch ( r . length ( ) )
{
case ( 16 ) : // Response to pkt0
2021-02-04 18:52:00 +00:00
if ( r . mid ( 0 , 8 ) = = QByteArrayLiteral ( " \x10 \x00 \x00 \x00 \x06 \x00 \x01 \x00 " ) )
2021-02-03 20:00:40 +00:00
{
2021-02-13 23:25:24 +00:00
// Update remoteId
remoteId = qFromBigEndian < quint32 > ( r . mid ( 8 , 4 ) ) ;
sendOpenClose ( false ) ;
2021-02-03 20:00:40 +00:00
}
break ;
default :
if ( r . length ( ) > 21 ) {
2021-02-05 20:26:18 +00:00
// First check if we are missing any packets?
uint16_t gotSeq = qFromLittleEndian < quint16 > ( r . mid ( 6 , 2 ) ) ;
if ( lastReceivedSeq = = 0 | | lastReceivedSeq > gotSeq ) {
lastReceivedSeq = gotSeq ;
}
for ( uint16_t f = lastReceivedSeq + 1 ; f < gotSeq ; f + + ) {
// Do we need to request a retransmit?
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Missing Sequence: ( " < < r . length ( ) < < " ) " < < f ;
}
2021-02-14 16:14:56 +00:00
2021-02-05 20:26:18 +00:00
lastReceivedSeq = gotSeq ;
2021-02-03 20:00:40 +00:00
quint8 temp = r [ 0 ] - 0x15 ;
if ( ( quint8 ) r [ 16 ] = = 0xc1 & & ( quint8 ) r [ 17 ] = = temp )
2021-02-05 17:40:58 +00:00
{
2021-02-13 23:25:24 +00:00
emit receive ( r . mid ( 21 ) ) ;
2021-02-05 17:40:58 +00:00
}
2021-02-03 20:00:40 +00:00
}
break ;
}
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-02-13 23:25:24 +00:00
udpAudio : : udpAudio ( QHostAddress local , QHostAddress ip , quint16 audioPort , quint16 buffer , quint16 rxsample , quint8 rxcodec , quint16 txsample , quint8 txcodec )
2021-02-03 20:00:40 +00:00
{
qDebug ( ) < < " 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 ;
this - > bufferSize = buffer ;
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-02-12 11:04:42 +00:00
connect ( this , SIGNAL ( setupRxAudio ( quint8 , quint8 , quint16 , quint16 , bool , bool ) ) , rxaudio , SLOT ( init ( quint8 , quint8 , quint16 , quint16 , bool , bool ) ) ) ;
2021-02-12 23:56:02 +00:00
//connect(this, SIGNAL(haveAudioData(QByteArray)), rxaudio, SLOT(incomingAudio(QByteArray)));
2021-02-08 16:53:26 +00:00
connect ( this , SIGNAL ( haveChangeBufferSize ( quint16 ) ) , rxaudio , SLOT ( changeBufferSize ( 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 ) ;
connect ( this , SIGNAL ( setupTxAudio ( quint8 , quint8 , quint16 , quint16 , bool , bool ) ) , txaudio , SLOT ( init ( quint8 , quint8 , quint16 , quint16 , bool , bool ) ) ) ;
2021-02-12 23:56:02 +00:00
//connect(txaudio, SIGNAL(haveAudioData(QByteArray)), this, SLOT(sendTxAudio(QByteArray)));
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-13 23:25:24 +00:00
sendAreYouThere ( ) ; // No need to send periodic are you there as we know they are!
connect ( & pingTimer , & QTimer : : timeout , this , & udpBase : : sendPing ) ;
2021-02-14 07:53:55 +00:00
pingTimer . start ( PING_PERIOD ) ; // send ping packets every 100ms
2021-02-13 23:25:24 +00:00
connect ( & txAudioTimer , & QTimer : : timeout , this , & udpAudio : : sendTxAudio ) ;
2021-02-14 07:53:55 +00:00
txAudioTimer . start ( TXAUDIO_PERIOD ) ;
2021-02-13 23:25:24 +00:00
2021-02-14 07:15:49 +00:00
emit setupTxAudio ( txNumSamples , txChannelCount , txSampleRate , bufferSize , txIsUlawCodec , true ) ;
emit setupRxAudio ( rxNumSamples , rxChannelCount , rxSampleRate , bufferSize , rxIsUlawCodec , false ) ;
2021-02-03 20:00:40 +00:00
}
2021-02-05 17:40:58 +00:00
udpAudio : : ~ udpAudio ( )
{
2021-02-13 23:25:24 +00:00
if ( txAudioTimer . isActive ( ) )
{
txAudioTimer . stop ( ) ;
}
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-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
{
quint8 p [ ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff ) ,
2021-02-11 19:18:35 +00:00
0x80 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
2021-02-12 20:42:56 +00:00
//if (((txCodec == 0x01 || txCodec == 0x02) && audio.length() != 960) || (txCodec == 0x04 && audio.length() != 1920)) {
// qDebug() << "Unsupported TX audio length :" << audio.length() << " With codec: " << txCodec;
//}
2021-02-13 11:04:26 +00:00
if ( txaudio - > chunkAvailable ) {
QByteArray audio ;
txaudio - > getNextAudioChunk ( audio ) ;
2021-02-12 23:56:02 +00:00
int counter = 0 ;
2021-02-13 11:04:26 +00:00
while ( counter < audio . length ( ) ) {
2021-02-12 23:56:02 +00:00
QByteArray tx = QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) ;
QByteArray partial = audio . mid ( counter , 1364 ) ;
tx . append ( partial ) ;
tx [ 0 ] = static_cast < quint8 > ( tx . length ( ) & 0xff ) ;
tx [ 1 ] = static_cast < quint8 > ( tx . length ( ) > > 8 & 0xff ) ;
tx [ 18 ] = static_cast < quint8 > ( sendAudioSeq > > 8 & 0xff ) ;
tx [ 19 ] = static_cast < quint8 > ( sendAudioSeq & 0xff ) ;
tx [ 22 ] = static_cast < quint8 > ( partial . length ( ) > > 8 & 0xff ) ;
tx [ 23 ] = static_cast < quint8 > ( partial . length ( ) & 0xff ) ;
counter = counter + partial . length ( ) ;
//qDebug() << "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-13 11:04:26 +00:00
}
2021-02-05 17:40:58 +00:00
}
2021-02-03 20:00:40 +00:00
2021-02-08 16:53:26 +00:00
void udpAudio : : changeBufferSize ( quint16 value )
{
emit haveChangeBufferSize ( value ) ;
}
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 ( ) ;
//qDebug() << "Received: " << datagram.data();
QByteArray r = datagram . data ( ) ;
switch ( r . length ( ) )
{
2021-02-13 23:25:24 +00:00
case ( 16 ) : // Response to idle packet handled in udpBase
2021-02-03 20:00:40 +00:00
break ;
default :
2021-02-09 12:43:28 +00:00
/* 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
*/
if ( r . mid ( 0 , 2 ) = = QByteArrayLiteral ( " \x6c \x05 " ) | |
r . mid ( 0 , 2 ) = = QByteArrayLiteral ( " \x44 \x02 " ) | |
r . mid ( 0 , 2 ) = = QByteArrayLiteral ( " \xd8 \x03 " ) | |
r . mid ( 0 , 2 ) = = QByteArrayLiteral ( " \x70 \x04 " ) )
2021-02-03 20:00:40 +00:00
{
2021-02-14 16:14:56 +00:00
// First check if we are missing any packets as seq should be sequential.
2021-02-03 20:00:40 +00:00
uint16_t gotSeq = qFromLittleEndian < quint16 > ( r . mid ( 6 , 2 ) ) ;
2021-02-05 20:26:18 +00:00
if ( lastReceivedSeq = = 0 | | lastReceivedSeq > gotSeq ) {
lastReceivedSeq = gotSeq ;
2021-02-03 20:00:40 +00:00
}
2021-02-06 10:54:20 +00:00
for ( uint16_t f = lastReceivedSeq + 1 ; f < gotSeq ; f + + ) {
2021-02-05 20:26:18 +00:00
// Do we need to request a retransmit?
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Missing Sequence: ( " < < r . length ( ) < < " ) " < < f ;
2021-02-03 20:00:40 +00:00
}
2021-02-05 20:26:18 +00:00
lastReceivedSeq = gotSeq ;
2021-02-12 23:56:02 +00:00
rxaudio - > incomingAudio ( r . mid ( 24 ) ) ;
2021-02-03 20:00:40 +00:00
}
break ;
}
2021-02-04 18:52: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
{
udp = new QUdpSocket ( this ) ;
udp - > bind ( ) ; // Bind to random port.
localPort = udp - > localPort ( ) ;
qDebug ( ) < < " UDP Stream bound to local port: " < < localPort < < " remote port: " < < port ;
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-04 19:53:48 +00:00
}
2021-02-13 23:25:24 +00:00
2021-02-04 19:53:48 +00:00
udpBase : : ~ udpBase ( )
{
qDebug ( ) < < " Closing UDP stream : " < < radioIP . toString ( ) < < " : " < < port ;
2021-02-07 12:59:41 +00:00
if ( udp ! = Q_NULLPTR ) {
2021-02-13 23:25:24 +00:00
sendPacketDisconnect ( ) ;
2021-02-04 19:53:48 +00:00
udp - > close ( ) ;
delete udp ;
}
2021-02-13 23:25:24 +00:00
if ( pingTimer . isActive ( ) )
2021-02-07 12:59:41 +00:00
{
2021-02-13 23:25:24 +00:00
pingTimer . stop ( ) ;
2021-02-07 12:59:41 +00:00
}
2021-02-13 23:25:24 +00:00
if ( idleTimer . isActive ( ) )
2021-02-07 12:59:41 +00:00
{
2021-02-13 23:25:24 +00:00
idleTimer . stop ( ) ;
2021-02-07 12:59:41 +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
{
switch ( r . length ( ) )
{
2021-02-13 23:25:24 +00:00
case ( 16 ) : // Empty response used for simple comms and retransmit requests.
if ( r . mid ( 0 , 8 ) = = QByteArrayLiteral ( " \x10 \x00 \x00 \x00 \x04 \x00 \x00 \x00 " ) ) {
// If timer is active, stop it as they are obviously there!
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Received I am here " ;
2021-02-14 07:53:55 +00:00
areYouThereCounter = 0 ;
2021-02-13 23:25:24 +00:00
// I don't think that we will ever receive an "I am here" other than in response to "Are you there?"
remoteId = qFromBigEndian < quint32 > ( r . mid ( 8 , 4 ) ) ;
sendAreYouReady ( ) ;
}
else if ( r . mid ( 0 , 6 ) = = QByteArrayLiteral ( " \x10 \x00 \x00 \x00 \x00 \x00 " ) ) {
2021-02-05 21:23:00 +00:00
// Just get the seqnum and ignore the rest.
lastReceivedSeq = qFromLittleEndian < quint16 > ( r . mid ( 6 , 2 ) ) ;
2021-02-04 18:52:00 +00:00
}
2021-02-13 23:25:24 +00:00
else if ( r . mid ( 0 , 6 ) = = QByteArrayLiteral ( " \x10 \x00 \x00 \x00 \x01 \x00 " ) ) {
// retransmit request
2021-02-05 13:16:48 +00:00
// Send an idle with the requested seqnum if not found.
2021-02-04 18:52:00 +00:00
uint16_t gotSeq = qFromLittleEndian < quint16 > ( r . mid ( 6 , 2 ) ) ;
2021-02-05 15:49:08 +00:00
bool found = false ;
for ( int f = txSeqBuf . length ( ) - 1 ; f > = 0 ; f - - )
2021-02-04 18:52:00 +00:00
{
2021-02-14 10:40:47 +00:00
packetsLost + + ;
2021-02-04 18:52:00 +00:00
if ( txSeqBuf [ f ] . seqNum = = gotSeq ) {
2021-02-14 10:40:47 +00:00
//qDebug() << this->metaObject()->className() << ": retransmitting packet :" << gotSeq << " (len=" << txSeqBuf[f].data.length() << ")";
2021-02-13 23:25:24 +00:00
QMutexLocker locker ( & mutex ) ;
2021-02-04 18:52:00 +00:00
udp - > writeDatagram ( txSeqBuf [ f ] . data , radioIP , port ) ;
2021-02-05 15:49:08 +00:00
found = true ;
2021-02-04 18:52:00 +00:00
break ;
}
}
2021-02-05 15:49:08 +00:00
if ( ! found )
2021-02-04 18:52:00 +00:00
{
// Packet was not found in buffer
2021-02-14 10:40:47 +00:00
//qDebug() << this->metaObject()->className() << ": Could not find requested packet " << gotSeq << ", sending idle.";
2021-02-13 23:25:24 +00:00
sendIdle ( false , gotSeq ) ;
2021-02-04 18:52:00 +00:00
}
}
else if ( r . mid ( 0 , 6 ) = = QByteArrayLiteral ( " \x18 \x00 \x00 \x00 \x01 \x00 " ) )
2021-02-05 13:16:48 +00:00
{ // retransmit range request, can contain multiple ranges.
2021-02-04 18:52:00 +00:00
for ( int f = 16 ; f < r . length ( ) - 4 ; f = f + 4 )
{
2021-02-05 13:16:48 +00:00
quint16 start = qFromLittleEndian < quint16 > ( r . mid ( f , 2 ) ) ;
quint16 end = qFromLittleEndian < quint16 > ( r . mid ( f + 2 , 2 ) ) ;
2021-02-14 10:40:47 +00:00
packetsLost = packetsLost + ( end - start ) ;
2021-02-05 15:49:08 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Retransmit range request for: " < < start < < " to " < < end ;
2021-02-05 13:16:48 +00:00
for ( quint16 gotSeq = start ; gotSeq < = end ; gotSeq + + )
2021-02-04 18:52:00 +00:00
{
2021-02-05 15:49:08 +00:00
bool found = false ;
for ( int h = txSeqBuf . length ( ) - 1 ; h > = 0 ; h - - )
2021-02-05 13:16:48 +00:00
if ( txSeqBuf [ h ] . seqNum = = gotSeq ) {
2021-02-14 10:40:47 +00:00
//qDebug() << this->metaObject()->className() << ": retransmitting packet :" << gotSeq << " (len=" << txSeqBuf[f].data.length() << ")";
2021-02-13 23:25:24 +00:00
QMutexLocker locker ( & mutex ) ;
2021-02-05 13:16:48 +00:00
udp - > writeDatagram ( txSeqBuf [ h ] . data , radioIP , port ) ;
2021-02-05 15:49:08 +00:00
found = true ;
2021-02-05 13:16:48 +00:00
break ;
}
2021-02-05 15:49:08 +00:00
if ( ! found )
2021-02-05 13:16:48 +00:00
{
2021-02-14 10:40:47 +00:00
//qDebug() << this->metaObject()->className() << ": Could not find requested packet " << gotSeq << ", sending idle.";
2021-02-13 23:25:24 +00:00
sendIdle ( false , gotSeq ) ;
2021-02-05 13:16:48 +00:00
}
2021-02-04 18:52:00 +00:00
}
}
}
break ;
2021-02-13 23:25:24 +00:00
case ( 21 ) :
2021-02-04 18:52:00 +00:00
if ( r . mid ( 1 , 5 ) = = QByteArrayLiteral ( " \x00 \x00 \x00 \x07 \x00 " ) )
{
2021-02-13 23:25:24 +00:00
// It is a ping request/response
2021-02-04 18:52:00 +00:00
uint16_t gotSeq = qFromLittleEndian < quint16 > ( r . mid ( 6 , 2 ) ) ;
if ( r [ 16 ] = = ( char ) 0x00 )
{
2021-02-09 12:43:28 +00:00
const quint8 p [ ] = { 0x15 , 0x00 , 0x00 , 0x00 , 0x07 , 0x00 , static_cast < quint8 > ( gotSeq & 0xff ) , static_cast < quint8 > ( ( gotSeq > > 8 ) & 0xff ) ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff ) ,
2021-02-09 12:43:28 +00:00
0x01 , static_cast < quint8 > ( r [ 17 ] ) , static_cast < quint8 > ( r [ 18 ] ) , static_cast < quint8 > ( r [ 19 ] ) , static_cast < quint8 > ( r [ 20 ] )
2021-02-04 18:52:00 +00:00
} ;
2021-02-13 23:25:24 +00:00
QMutexLocker locker ( & mutex ) ;
2021-02-04 21:12:38 +00:00
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) , radioIP , port ) ;
2021-02-13 23:25:24 +00:00
}
else if ( r [ 16 ] = = ( char ) 0x01 ) {
if ( gotSeq = = pingSendSeq )
{
// This is response to OUR request so increment counter
pingSendSeq + + ;
}
else {
2021-02-14 15:30:34 +00:00
// Not sure what to do here, need to spend more time with the protocol but try sending ping with same seq next time?
//qDebug() << "Received out-of-sequence ping response. Sent:" << pingSendSeq << " received " << gotSeq;
2021-02-13 23:25:24 +00:00
}
} else {
qDebug ( ) < < " Unhandled response to ping. I have never seen this! 0x10= " < < r [ 16 ] ;
}
2021-02-04 18:52:00 +00:00
}
break ;
default :
break ;
}
}
2021-02-13 23:25:24 +00:00
void udpBase : : sendIdle ( bool tracked = true , quint16 seq = 0 )
2021-02-03 20:00:40 +00:00
{
2021-02-09 12:43:28 +00:00
quint8 p [ ] = { 0x10 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff )
2021-02-03 20:00:40 +00:00
} ;
2021-02-13 23:25:24 +00:00
lastControlPacketSentTime = QDateTime : : currentDateTime ( ) ; // Is this used?
2021-02-04 13:12:08 +00:00
if ( ! tracked ) {
p [ 6 ] = seq & 0xff ;
p [ 7 ] = ( seq > > 8 ) & 0xff ;
2021-02-13 23:25:24 +00:00
QMutexLocker locker ( & mutex ) ;
2021-02-04 13:12:08 +00:00
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) , radioIP , port ) ;
}
else {
2021-02-13 23:25:24 +00:00
sendTrackedPacket ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) ) ;
2021-02-04 13:12:08 +00:00
}
2021-02-14 07:53:55 +00:00
if ( idleTimer . isActive ( ) ) {
idleTimer . start ( IDLE_PERIOD ) ; // Reset idle counter if it's running
}
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-05 14:38:30 +00:00
//qDebug() << this->metaObject()->className() << " tx buffer size:" << txSeqBuf.length();
2021-02-03 20:00:40 +00:00
2021-02-13 23:25:24 +00:00
const quint8 p [ ] = { 0x15 , 0x00 , 0x00 , 0x00 , 0x07 , 0x00 , static_cast < quint8 > ( pingSendSeq & 0xff ) , static_cast < quint8 > ( pingSendSeq > > 8 & 0xff ) ,
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff ) ,
2021-02-09 12:43:28 +00:00
0x00 , static_cast < quint8 > ( rand ( ) ) , static_cast < quint8 > ( innerSendSeq & 0xff ) , static_cast < quint8 > ( innerSendSeq > > 8 & 0xff ) , 0x06
2021-02-03 20:00:40 +00:00
} ;
2021-02-06 10:54:20 +00:00
//qDebug() << this->metaObject()->className() << ": Send pkt7: " << QByteArray::fromRawData((const char*)p, sizeof(p));
2021-02-13 23:25:24 +00:00
lastPingSentTime = QDateTime : : currentDateTime ( ) ;
QMutexLocker locker ( & mutex ) ;
2021-02-03 20:00:40 +00:00
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) , radioIP , port ) ;
2021-02-06 10:54:20 +00:00
innerSendSeq + + ;
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-05 13:16:48 +00:00
s . timeSent = time ( NULL ) ;
2021-02-04 13:12:08 +00:00
s . data = ( d ) ;
txSeqBuf . append ( s ) ;
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-02-13 23:25:24 +00:00
QMutexLocker locker ( & mutex ) ;
udp - > writeDatagram ( d , radioIP , port ) ;
if ( idleTimer . isActive ( ) ) {
2021-02-14 07:53:55 +00:00
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-13 23:25:24 +00:00
void udpBase : : purgeOldEntries ( )
2021-02-03 20:00:40 +00:00
{
for ( int f = txSeqBuf . length ( ) - 1 ; f > = 0 ; f - - )
{
2021-02-13 23:25:24 +00:00
if ( difftime ( time ( NULL ) , txSeqBuf [ f ] . timeSent ) > PURGE_SECONDS )
2021-02-05 17:40:58 +00:00
{
2021-02-03 20:00:40 +00:00
txSeqBuf . removeAt ( f ) ;
2021-02-05 17:40:58 +00:00
}
2021-02-03 20:00:40 +00:00
}
}
2021-02-13 23:25:24 +00:00
/// <summary>
/// This function is used by all sockets and expects an "I am here" response.
/// </summary>
void udpBase : : sendAreYouThere ( )
2021-02-03 20:00:40 +00:00
{
2021-02-13 23:25:24 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Sending Are You There... " ;
2021-02-09 12:43:28 +00:00
const quint8 p [ ] = { 0x10 , 0x00 , 0x00 , 0x00 , 0x03 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff )
2021-02-03 20:00:40 +00:00
} ;
2021-02-13 23:25:24 +00:00
QMutexLocker locker ( & mutex ) ;
2021-02-03 20:00:40 +00:00
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) , radioIP , port ) ;
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
/// <summary>
/// Once an "I am here" response is received, send this
/// </summary>
void udpBase : : sendAreYouReady ( )
2021-02-03 20:00:40 +00:00
{
2021-02-13 23:25:24 +00:00
qDebug ( ) < < this - > metaObject ( ) - > className ( ) < < " : Sending Are you ready? " ;
2021-02-09 12:43:28 +00:00
const quint8 p [ ] = { 0x10 , 0x00 , 0x00 , 0x00 , 0x06 , 0x00 , 0x01 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff )
2021-02-03 20:00:40 +00:00
} ;
2021-02-13 23:25:24 +00:00
QMutexLocker locker ( & mutex ) ;
2021-02-03 20:00:40 +00:00
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) , radioIP , port ) ;
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 udpBase : : sendPacketDisconnect ( ) // Unmanaged packet
2021-02-03 20:00:40 +00:00
{
2021-02-13 23:25:24 +00:00
qDebug ( ) < < " Sending Stream Disconnect " ;
2021-02-03 20:00:40 +00:00
2021-02-09 12:43:28 +00:00
const quint8 p [ ] = { 0x10 , 0x00 , 0x00 , 0x00 , 0x05 , 0x00 , 0x00 , 0x00 ,
2021-02-13 23:25:24 +00:00
static_cast < quint8 > ( myId > > 24 & 0xff ) , static_cast < quint8 > ( myId > > 16 & 0xff ) , static_cast < quint8 > ( myId > > 8 & 0xff ) , static_cast < quint8 > ( myId & 0xff ) ,
static_cast < quint8 > ( remoteId > > 24 & 0xff ) , static_cast < quint8 > ( remoteId > > 16 & 0xff ) , static_cast < quint8 > ( remoteId > > 8 & 0xff ) , static_cast < quint8 > ( remoteId & 0xff )
2021-02-03 20:00:40 +00:00
} ;
2021-02-13 23:25:24 +00:00
QMutexLocker locker ( & mutex ) ;
udp - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p , sizeof ( p ) ) , radioIP , port ) ;
return ;
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>
quint8 * passcode ( QString str )
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-09 12:43:28 +00:00
quint8 * res = new quint8 [ 16 ] ;
2021-02-03 20:00:40 +00:00
memset ( res , 0 , 16 ) ; // Make sure res buffer is empty!
QByteArray ba = str . toLocal8Bit ( ) ;
uchar * ascii = ( uchar * ) ba . constData ( ) ;
for ( int i = 0 ; i < str . length ( ) & & i < 16 ; i + + )
{
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-03 20:00:40 +00:00
res [ i ] = sequence [ p ] ;
}
return res ;
}
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