2013-11-05 16:46:17 +01:00
// STL includes
# include <cstring>
# include <iostream>
2014-05-04 11:41:55 +02:00
// Qt includes
# include <QTimer>
2017-02-09 20:10:57 +01:00
# include <QDateTime>
# include <QFile>
# include <QSerialPortInfo>
2014-05-04 11:41:55 +02:00
2013-11-05 16:46:17 +01:00
// Local Hyperion includes
2016-08-28 07:12:48 +02:00
# include "ProviderRs232.h"
2013-11-05 16:46:17 +01:00
2016-10-08 08:14:36 +02:00
ProviderRs232 : : ProviderRs232 ( )
2016-08-23 20:07:12 +02:00
: _rs232Port ( this )
2019-12-15 13:43:50 +01:00
, _writeTimeout ( this )
2016-07-20 16:04:56 +02:00
, _blockedForDelay ( false )
, _stateChanged ( true )
2016-09-25 22:20:01 +02:00
, _bytesToWrite ( 0 )
, _frameDropCounter ( 0 )
, _lastError ( QSerialPort : : NoError )
2017-02-09 20:10:57 +01:00
, _preOpenDelayTimeOut ( 0 )
, _preOpenDelay ( 2000 )
, _enableAutoDeviceName ( false )
2013-11-05 16:46:17 +01:00
{
2016-07-20 23:26:47 +02:00
connect ( & _rs232Port , SIGNAL ( error ( QSerialPort : : SerialPortError ) ) , this , SLOT ( error ( QSerialPort : : SerialPortError ) ) ) ;
2016-09-25 22:20:01 +02:00
connect ( & _rs232Port , SIGNAL ( bytesWritten ( qint64 ) ) , this , SLOT ( bytesWritten ( qint64 ) ) ) ;
connect ( & _rs232Port , SIGNAL ( readyRead ( ) ) , this , SLOT ( readyRead ( ) ) ) ;
2020-02-10 15:21:58 +01:00
2019-12-15 13:43:50 +01:00
_writeTimeout . setInterval ( 5000 ) ;
_writeTimeout . setSingleShot ( true ) ;
connect ( & _writeTimeout , SIGNAL ( timeout ( ) ) , this , SLOT ( writeTimeout ( ) ) ) ;
2016-07-20 23:26:47 +02:00
}
2016-10-13 21:59:58 +02:00
bool ProviderRs232 : : init ( const QJsonObject & deviceConfig )
2016-08-23 20:07:12 +02:00
{
closeDevice ( ) ;
2016-12-02 12:07:24 +01:00
2020-02-10 15:21:58 +01:00
bool isInitOK = LedDevice : : init ( deviceConfig ) ;
2016-12-02 12:07:24 +01:00
2017-02-09 20:10:57 +01:00
_deviceName = deviceConfig [ " output " ] . toString ( " auto " ) ;
_enableAutoDeviceName = _deviceName = = " auto " ;
2016-10-13 21:59:58 +02:00
_baudRate_Hz = deviceConfig [ " rate " ] . toInt ( ) ;
2017-02-09 20:10:57 +01:00
_delayAfterConnect_ms = deviceConfig [ " delayAfterConnect " ] . toInt ( 1500 ) ;
_preOpenDelay = deviceConfig [ " delayBeforeConnect " ] . toInt ( 1500 ) ;
2016-08-23 20:07:12 +02:00
2020-02-10 15:21:58 +01:00
return isInitOK ;
}
void ProviderRs232 : : close ( )
{
LedDevice : : close ( ) ;
// LedDevice specific closing activites
closeDevice ( ) ;
2016-08-23 20:07:12 +02:00
}
2017-02-09 20:10:57 +01:00
QString ProviderRs232 : : findSerialDevice ( )
{
// take first available usb serial port - currently no probing!
for ( auto port : QSerialPortInfo : : availablePorts ( ) )
{
if ( port . hasProductIdentifier ( ) & & port . hasVendorIdentifier ( ) & & ! port . isBusy ( ) )
{
Info ( _log , " found serial device: %s " , port . systemLocation ( ) . toLocal8Bit ( ) . constData ( ) ) ;
return port . systemLocation ( ) ;
}
}
return " " ;
}
2016-09-25 22:20:01 +02:00
void ProviderRs232 : : bytesWritten ( qint64 bytes )
{
2019-12-15 13:43:50 +01:00
_bytesToWrite - = bytes ;
if ( _bytesToWrite < = 0 )
2016-09-25 22:20:01 +02:00
{
_blockedForDelay = false ;
2019-12-15 13:43:50 +01:00
_writeTimeout . stop ( ) ;
2016-09-25 22:20:01 +02:00
}
}
void ProviderRs232 : : readyRead ( )
{
2017-02-09 20:10:57 +01:00
emit receivedData ( _rs232Port . readAll ( ) ) ;
2017-02-16 07:33:58 +01:00
//Debug(_log, "received data");
2016-09-25 22:20:01 +02:00
}
2016-08-28 07:12:48 +02:00
void ProviderRs232 : : error ( QSerialPort : : SerialPortError error )
2016-07-20 23:26:47 +02:00
{
if ( error ! = QSerialPort : : NoError )
{
2016-09-25 22:20:01 +02:00
if ( _lastError ! = error )
2016-07-20 23:26:47 +02:00
{
2016-09-25 22:20:01 +02:00
_lastError = error ;
switch ( error )
{
2016-07-20 23:26:47 +02:00
case QSerialPort : : DeviceNotFoundError :
Error ( _log , " An error occurred while attempting to open an non-existing device. " ) ; break ;
case QSerialPort : : PermissionError :
2017-02-09 20:10:57 +01:00
Error ( _log , " An error occurred while attempting to open an already opened device by another process or a user not having enough permission and credentials to open. Device disabled. " ) ;
_deviceReady = false ;
break ;
2016-07-20 23:26:47 +02:00
case QSerialPort : : OpenError :
Error ( _log , " An error occurred while attempting to open an already opened device in this object. " ) ; break ;
case QSerialPort : : NotOpenError :
Error ( _log , " This error occurs when an operation is executed that can only be successfully performed if the device is open. " ) ; break ;
case QSerialPort : : ParityError :
2016-09-25 22:20:01 +02:00
Error ( _log , " Parity error detected by the hardware while reading data. " ) ; break ;
2016-07-20 23:26:47 +02:00
case QSerialPort : : FramingError :
2016-09-25 22:20:01 +02:00
Error ( _log , " Framing error detected by the hardware while reading data. " ) ; break ;
2016-07-20 23:26:47 +02:00
case QSerialPort : : BreakConditionError :
2016-09-25 22:20:01 +02:00
Error ( _log , " Break condition detected by the hardware on the input line. " ) ; break ;
2016-07-20 23:26:47 +02:00
case QSerialPort : : WriteError :
Error ( _log , " An I/O error occurred while writing the data. " ) ; break ;
case QSerialPort : : ReadError :
Error ( _log , " An I/O error occurred while reading the data. " ) ; break ;
case QSerialPort : : ResourceError :
Error ( _log , " An I/O error occurred when a resource becomes unavailable, e.g. when the device is unexpectedly removed from the system. " ) ; break ;
case QSerialPort : : UnsupportedOperationError :
2017-02-09 20:10:57 +01:00
Error ( _log , " The requested device operation is not supported or prohibited by the running operating system. Device disabled. " ) ;
_deviceReady = false ;
break ;
2016-07-20 23:26:47 +02:00
case QSerialPort : : TimeoutError :
Error ( _log , " A timeout error occurred. " ) ; break ;
2017-02-09 20:10:57 +01:00
default :
Error ( _log , " An unidentified error occurred. Device disabled. (%d) " , error ) ;
_deviceReady = false ;
2016-09-25 22:20:01 +02:00
}
_rs232Port . clearError ( ) ;
2020-02-10 15:21:58 +01:00
this - > setInError ( " Rs232 SerialPortError, see details in previous log lines! " ) ;
2016-09-25 22:20:01 +02:00
closeDevice ( ) ;
2016-07-20 23:26:47 +02:00
}
}
2013-11-05 16:46:17 +01:00
}
2016-08-28 07:12:48 +02:00
ProviderRs232 : : ~ ProviderRs232 ( )
2013-11-05 16:46:17 +01:00
{
2016-07-20 23:26:47 +02:00
disconnect ( & _rs232Port , SIGNAL ( error ( QSerialPort : : SerialPortError ) ) , this , SLOT ( error ( QSerialPort : : SerialPortError ) ) ) ;
2016-08-23 20:07:12 +02:00
}
2016-08-28 07:12:48 +02:00
void ProviderRs232 : : closeDevice ( )
2016-08-23 20:07:12 +02:00
{
2019-12-15 13:43:50 +01:00
_writeTimeout . stop ( ) ;
2013-11-05 16:46:17 +01:00
if ( _rs232Port . isOpen ( ) )
2016-07-20 16:04:56 +02:00
{
2013-11-05 16:46:17 +01:00
_rs232Port . close ( ) ;
2017-02-09 20:10:57 +01:00
Debug ( _log , " Close UART: %s " , _deviceName . toLocal8Bit ( ) . constData ( ) ) ;
2016-07-20 16:04:56 +02:00
}
2019-12-15 13:43:50 +01:00
_stateChanged = true ;
_bytesToWrite = 0 ;
_blockedForDelay = false ;
_deviceReady = false ;
2013-11-05 16:46:17 +01:00
}
2016-08-28 07:12:48 +02:00
int ProviderRs232 : : open ( )
2013-11-05 16:46:17 +01:00
{
2020-02-10 15:21:58 +01:00
int retval = - 1 ;
_deviceReady = false ;
2016-06-23 00:11:09 +02:00
2020-02-10 15:21:58 +01:00
// General initialisation and configuration of LedDevice
if ( init ( _devConfig ) )
{
if ( tryOpen ( _delayAfterConnect_ms ) )
{
// Everything is OK -> enable device
_deviceReady = true ;
setEnable ( true ) ;
retval = 0 ;
}
else
{
this - > setInError ( " Error opening device! " ) ;
}
}
return retval ;
}
2014-05-04 11:31:13 +02:00
2016-09-25 22:20:01 +02:00
bool ProviderRs232 : : tryOpen ( const int delayAfterConnect_ms )
2016-06-23 00:11:09 +02:00
{
2017-02-09 20:10:57 +01:00
if ( _deviceName . isEmpty ( ) | | _rs232Port . portName ( ) . isEmpty ( ) )
{
if ( _enableAutoDeviceName )
{
_deviceName = findSerialDevice ( ) ;
if ( _deviceName . isEmpty ( ) )
{
return false ;
}
}
Info ( _log , " Opening UART: %s " , _deviceName . toLocal8Bit ( ) . constData ( ) ) ;
_rs232Port . setPortName ( _deviceName ) ;
}
2016-06-23 00:11:09 +02:00
if ( ! _rs232Port . isOpen ( ) )
{
2017-02-09 20:10:57 +01:00
_frameDropCounter = 0 ;
if ( QFile : : exists ( _deviceName ) )
2014-05-04 11:31:13 +02:00
{
2017-02-09 20:10:57 +01:00
if ( _preOpenDelayTimeOut > QDateTime : : currentMSecsSinceEpoch ( ) )
2016-07-20 16:04:56 +02:00
{
2017-02-09 20:10:57 +01:00
return false ;
2016-07-20 16:04:56 +02:00
}
2017-02-09 20:10:57 +01:00
if ( ! _rs232Port . open ( QIODevice : : ReadWrite ) )
{
if ( _stateChanged )
{
Error ( _log , " Unable to open RS232 device (%s) " , _deviceName . toLocal8Bit ( ) . constData ( ) ) ;
_stateChanged = false ;
}
return false ;
}
Debug ( _log , " Setting baud rate to %d " , _baudRate_Hz ) ;
_rs232Port . setBaudRate ( _baudRate_Hz ) ;
_stateChanged = true ;
_preOpenDelayTimeOut = 0 ;
}
else
{
_preOpenDelayTimeOut = QDateTime : : currentMSecsSinceEpoch ( ) + _preOpenDelay ;
2016-06-23 00:11:09 +02:00
return false ;
2014-05-04 11:31:13 +02:00
}
2013-11-05 16:46:17 +01:00
}
2016-07-20 16:04:56 +02:00
2016-09-25 22:20:01 +02:00
if ( delayAfterConnect_ms > 0 )
2013-11-05 16:46:17 +01:00
{
2016-06-23 00:11:09 +02:00
_blockedForDelay = true ;
2016-09-25 22:20:01 +02:00
QTimer : : singleShot ( delayAfterConnect_ms , this , SLOT ( unblockAfterDelay ( ) ) ) ;
Debug ( _log , " Device blocked for %d ms " , delayAfterConnect_ms ) ;
2013-11-05 16:46:17 +01:00
}
2016-06-23 00:11:09 +02:00
return _rs232Port . isOpen ( ) ;
2013-11-05 16:46:17 +01:00
}
2016-06-23 00:11:09 +02:00
2016-09-25 22:20:01 +02:00
int ProviderRs232 : : writeBytes ( const qint64 size , const uint8_t * data )
2013-11-05 16:46:17 +01:00
{
2016-09-25 22:20:01 +02:00
if ( ! _blockedForDelay )
2016-08-14 10:46:44 +02:00
{
2016-09-25 22:20:01 +02:00
if ( ! _rs232Port . isOpen ( ) )
{
2016-10-08 08:14:36 +02:00
return tryOpen ( 5000 ) ? 0 : - 1 ;
2016-09-25 22:20:01 +02:00
}
2014-05-04 11:41:55 +02:00
2016-11-26 22:34:46 +01:00
if ( _frameDropCounter > 5 )
2016-09-25 22:20:01 +02:00
{
Debug ( _log , " %d frames dropped " , _frameDropCounter ) ;
}
_frameDropCounter = 0 ;
_blockedForDelay = true ;
_bytesToWrite = size ;
qint64 bytesWritten = _rs232Port . write ( reinterpret_cast < const char * > ( data ) , size ) ;
if ( bytesWritten = = - 1 | | bytesWritten ! = size )
{
Warning ( _log , " failed writing data " ) ;
QTimer : : singleShot ( 500 , this , SLOT ( unblockAfterDelay ( ) ) ) ;
return - 1 ;
}
2019-12-15 13:43:50 +01:00
_writeTimeout . start ( ) ;
2013-11-05 16:46:17 +01:00
}
2016-09-25 22:20:01 +02:00
else
2016-07-20 23:26:47 +02:00
{
2016-09-25 22:20:01 +02:00
_frameDropCounter + + ;
2016-07-20 23:26:47 +02:00
}
2013-12-17 20:28:57 +01:00
2016-07-20 23:26:47 +02:00
return 0 ;
2013-11-05 16:46:17 +01:00
}
2014-05-04 11:41:55 +02:00
2019-12-15 13:43:50 +01:00
void ProviderRs232 : : writeTimeout ( )
{
2020-02-10 15:21:58 +01:00
//Error(_log, "Timeout on write data to %s", _deviceName.toLocal8Bit().constData());
QString errortext = QString ( " Timeout on write data to %1 " ) . arg ( _deviceName ) ;
setInError ( errortext ) ;
close ( ) ;
2019-12-15 13:43:50 +01:00
}
2016-06-23 00:11:09 +02:00
2016-08-28 07:12:48 +02:00
void ProviderRs232 : : unblockAfterDelay ( )
2014-05-04 11:41:55 +02:00
{
_blockedForDelay = false ;
}