2016-05-30 23:58:31 +02:00
// STL includes
# include <cstring>
# include <cstdio>
# include <iostream>
2016-08-08 00:17:00 +02:00
# include <exception>
2016-05-30 23:58:31 +02:00
// Linux includes
# include <fcntl.h>
# include <QStringList>
# include <QUdpSocket>
# include <QHostInfo>
// Local Hyperion includes
2016-08-28 07:12:48 +02:00
# include "ProviderUdp.h"
2016-05-30 23:58:31 +02:00
2020-06-28 23:05:32 +02:00
const ushort MAX_PORT = 65535 ;
2016-09-22 09:19:31 +02:00
ProviderUdp : : ProviderUdp ( )
2016-08-23 20:07:12 +02:00
: LedDevice ( )
2020-02-10 15:21:58 +01:00
, _udpSocket ( nullptr )
, _port ( 1 )
, _defaultHost ( " 127.0.0.1 " )
2016-05-30 23:58:31 +02:00
{
2020-07-12 20:27:56 +02:00
_isDeviceReady = false ;
2017-04-09 22:28:32 +02:00
_latchTime_ms = 1 ;
2016-05-30 23:58:31 +02:00
}
2016-08-28 07:12:48 +02:00
ProviderUdp : : ~ ProviderUdp ( )
2016-05-30 23:58:31 +02:00
{
2020-06-28 23:05:32 +02:00
if ( _udpSocket ! = nullptr )
{
2020-07-12 20:27:56 +02:00
delete _udpSocket ;
2020-06-28 23:05:32 +02:00
}
2016-05-30 23:58:31 +02:00
}
2017-02-11 22:52:47 +01:00
bool ProviderUdp : : init ( const QJsonObject & deviceConfig )
2016-08-23 20:07:12 +02:00
{
2020-07-12 20:27:56 +02:00
bool isInitOK = false ;
2018-12-27 23:11:32 +01:00
2020-07-12 20:27:56 +02:00
// Initialise sub-class
if ( LedDevice : : init ( deviceConfig ) )
2016-08-27 14:05:09 +02:00
{
2020-07-12 20:27:56 +02:00
QString host = deviceConfig [ " host " ] . toString ( _defaultHost ) ;
if ( _address . setAddress ( host ) )
2016-08-27 14:05:09 +02:00
{
2020-08-09 17:43:23 +02:00
Debug ( _log , " Successfully parsed %s as an IP-address. " , QSTRING_CSTR ( _address . toString ( ) ) ) ;
2020-02-10 15:21:58 +01:00
}
else
{
2020-08-09 17:43:23 +02:00
QHostInfo hostInfo = QHostInfo : : fromName ( host ) ;
if ( hostInfo . error ( ) = = QHostInfo : : NoError )
2020-07-12 20:27:56 +02:00
{
2020-08-09 17:43:23 +02:00
_address = hostInfo . addresses ( ) . first ( ) ;
Debug ( _log , " Successfully resolved IP-address (%s) for hostname (%s). " , QSTRING_CSTR ( _address . toString ( ) ) , QSTRING_CSTR ( host ) ) ;
2020-07-12 20:27:56 +02:00
}
else
{
2020-08-09 17:43:23 +02:00
QString errortext = QString ( " Failed resolving IP-address for [%1], (%2) %3 " ) . arg ( host ) . arg ( hostInfo . error ( ) ) . arg ( hostInfo . errorString ( ) ) ;
this - > setInError ( errortext ) ;
isInitOK = false ;
2020-07-12 20:27:56 +02:00
}
2016-08-27 14:05:09 +02:00
}
2016-09-22 00:18:46 +02:00
2020-08-09 17:43:23 +02:00
if ( ! _isDeviceInError )
2020-07-12 20:27:56 +02:00
{
2020-08-09 17:43:23 +02:00
int config_port = deviceConfig [ " port " ] . toInt ( _port ) ;
if ( config_port < = 0 | | config_port > MAX_PORT )
{
QString errortext = QString ( " Invalid target port [%1]! " ) . arg ( config_port ) ;
this - > setInError ( errortext ) ;
isInitOK = false ;
}
else
{
_port = static_cast < int > ( config_port ) ;
Debug ( _log , " UDP socket will write to %s:%u " , QSTRING_CSTR ( _address . toString ( ) ) , _port ) ;
2018-12-27 23:11:32 +01:00
2020-08-09 17:43:23 +02:00
_udpSocket = new QUdpSocket ( this ) ;
2020-07-12 20:27:56 +02:00
2020-08-09 17:43:23 +02:00
isInitOK = true ;
}
2020-07-12 20:27:56 +02:00
}
}
2020-02-10 15:21:58 +01:00
return isInitOK ;
}
2020-07-12 20:27:56 +02:00
int ProviderUdp : : open ( )
2020-02-10 15:21:58 +01:00
{
2020-07-12 20:27:56 +02:00
int retval = - 1 ;
_isDeviceReady = false ;
2020-02-23 23:18:34 +01:00
2020-06-28 23:05:32 +02:00
// Try to bind the UDP-Socket
if ( _udpSocket ! = nullptr )
2020-02-23 23:18:34 +01:00
{
2020-08-09 17:43:23 +02:00
if ( _udpSocket - > state ( ) ! = QAbstractSocket : : BoundState )
2020-02-23 23:18:34 +01:00
{
2020-08-09 17:43:23 +02:00
QHostAddress localAddress = QHostAddress : : Any ;
quint16 localPort = 0 ;
if ( ! _udpSocket - > bind ( localAddress , localPort ) )
{
QString warntext = QString ( " Could not bind local address: %1, (%2) %3 " ) . arg ( localAddress . toString ( ) ) . arg ( _udpSocket - > error ( ) ) . arg ( _udpSocket - > errorString ( ) ) ;
Warning ( _log , " %s " , QSTRING_CSTR ( warntext ) ) ;
}
2020-02-23 23:18:34 +01:00
}
2020-07-12 20:27:56 +02:00
// Everything is OK, device is ready
_isDeviceReady = true ;
retval = 0 ;
2020-02-23 23:18:34 +01:00
}
2020-07-12 20:27:56 +02:00
else
2020-02-10 15:21:58 +01:00
{
2020-07-12 20:27:56 +02:00
this - > setInError ( " Open error. UDP Socket not initialised! " ) ;
2020-02-10 15:21:58 +01:00
}
return retval ;
}
2020-07-12 20:27:56 +02:00
int ProviderUdp : : close ( )
2020-02-10 15:21:58 +01:00
{
2020-07-12 20:27:56 +02:00
int retval = 0 ;
_isDeviceReady = false ;
2016-05-30 23:58:31 +02:00
2020-06-28 23:05:32 +02:00
if ( _udpSocket ! = nullptr )
2020-02-10 15:21:58 +01:00
{
2020-06-28 23:05:32 +02:00
// Test, if device requires closing
if ( _udpSocket - > isOpen ( ) )
{
Debug ( _log , " Close UDP-device: %s " , QSTRING_CSTR ( this - > getActiveDeviceType ( ) ) ) ;
_udpSocket - > close ( ) ;
// Everything is OK -> device is closed
}
2020-02-10 15:21:58 +01:00
}
2020-07-12 20:27:56 +02:00
return retval ;
2016-05-30 23:58:31 +02:00
}
2020-08-09 17:43:23 +02:00
int ProviderUdp : : writeBytes ( const unsigned size , const uint8_t * data )
2016-05-30 23:58:31 +02:00
{
2016-08-14 10:46:44 +02:00
qint64 retVal = _udpSocket - > writeDatagram ( ( const char * ) data , size , _address , _port ) ;
2020-06-28 23:05:32 +02:00
WarningIf ( ( retVal < 0 ) , _log , " &s " , QSTRING_CSTR ( QString
( " (%1:%2) Write Error: (%3) %4 " ) . arg ( _address . toString ( ) ) . arg ( _port ) . arg ( _udpSocket - > error ( ) ) . arg ( _udpSocket - > errorString ( ) ) ) ) ;
2016-05-30 23:58:31 +02:00
return retVal ;
}