2020-10-27 16:22:10 +00:00
///////////////////////////////////////////////////////////////////////////////////
2023-11-18 13:12:18 +01:00
// Copyright (C) 2020-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021 Christoph Berg <myon@debian.org> //
// Copyright (C) 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2022 Jiří Pinkava <jiri.pinkava@rossum.ai> //
2020-10-27 16:22:10 +00:00
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
2021-02-26 20:27:35 +00:00
#include <algorithm>
2021-05-30 12:52:01 +01:00
#include <cmath>
2021-02-26 20:27:35 +00:00
2020-10-27 16:22:10 +00:00
#include <QDebug>
#include <QSerialPort>
#include <QRegularExpression>
2024-02-14 13:21:26 +00:00
#include "maincore.h"
#include "SWGTargetAzimuthElevation.h"
2021-01-13 19:44:53 +00:00
#include "gs232controller.h"
2020-10-27 16:22:10 +00:00
#include "gs232controllerworker.h"
#include "gs232controllerreport.h"
MESSAGE_CLASS_DEFINITION ( GS232ControllerWorker :: MsgConfigureGS232ControllerWorker , Message )
MESSAGE_CLASS_DEFINITION ( GS232ControllerReport :: MsgReportAzAl , Message )
2024-02-14 13:21:26 +00:00
GS232ControllerWorker :: GS232ControllerWorker ( GS232Controller * controller ) :
m_controller ( controller ),
2020-10-27 16:22:10 +00:00
m_msgQueueToFeature ( nullptr ),
2021-11-23 12:13:24 +00:00
m_device ( nullptr ),
2021-11-25 09:28:59 +00:00
m_serialPort ( this ),
m_socket ( this ),
m_pollTimer ( this ),
2021-05-30 12:38:07 +01:00
m_lastAzimuth ( - 1.0f ),
m_lastElevation ( - 1.0f ),
2023-04-03 16:47:13 +01:00
m_controllerProtocol ( nullptr )
// m_spidSetOutstanding(false),
// m_spidSetSent(false),
// m_spidStatusSent(false),
// m_rotCtlDReadAz(false)
2020-10-27 16:22:10 +00:00
{
}
GS232ControllerWorker ::~ GS232ControllerWorker ()
{
2022-09-18 16:47:06 +01:00
qDebug () << "GS232ControllerWorker::~GS232ControllerWorker" ;
2022-09-20 21:13:12 +01:00
stopWork ();
2020-10-27 16:22:10 +00:00
m_inputMessageQueue . clear ();
2023-04-03 16:47:13 +01:00
delete m_controllerProtocol ;
2020-10-27 16:22:10 +00:00
}
2022-09-18 16:47:06 +01:00
void GS232ControllerWorker :: startWork ()
2020-10-27 16:22:10 +00:00
{
2022-09-18 16:47:06 +01:00
qDebug () << "GS232ControllerWorker::startWork" ;
2020-10-27 16:22:10 +00:00
connect ( & m_inputMessageQueue , SIGNAL ( messageEnqueued ()), this , SLOT ( handleInputMessages ()));
2021-11-23 12:13:24 +00:00
connect ( & m_serialPort , & QSerialPort :: readyRead , this , & GS232ControllerWorker :: readData );
connect ( & m_socket , & QTcpSocket :: readyRead , this , & GS232ControllerWorker :: readData );
if ( m_settings . m_connection == GS232ControllerSettings :: TCP ) {
m_device = openSocket ( m_settings );
} else {
m_device = openSerialPort ( m_settings );
2021-05-30 12:38:07 +01:00
}
2022-03-03 11:06:18 +00:00
connect ( & m_pollTimer , SIGNAL ( timeout ()), this , SLOT ( update ()));
m_pollTimer . start ( 1000 );
2022-09-18 16:47:06 +01:00
// Handle any messages already on the queue
handleInputMessages ();
2020-10-27 16:22:10 +00:00
}
void GS232ControllerWorker :: stopWork ()
{
2022-09-18 16:47:06 +01:00
qDebug () << "GS232ControllerWorker::stopWork" ;
2022-03-03 11:06:18 +00:00
disconnect ( & m_inputMessageQueue , SIGNAL ( messageEnqueued ()), this , SLOT ( handleInputMessages ()));
2022-11-18 10:55:15 +00:00
if ( m_device && m_device -> isOpen ())
{
2021-11-23 12:13:24 +00:00
m_device -> close ();
2022-11-18 10:55:15 +00:00
m_device = nullptr ;
2021-11-23 12:13:24 +00:00
}
disconnect ( & m_serialPort , & QSerialPort :: readyRead , this , & GS232ControllerWorker :: readData );
disconnect ( & m_socket , & QTcpSocket :: readyRead , this , & GS232ControllerWorker :: readData );
2022-03-03 11:06:18 +00:00
m_pollTimer . stop ();
disconnect ( & m_pollTimer , SIGNAL ( timeout ()), this , SLOT ( update ()));
2020-10-27 16:22:10 +00:00
}
void GS232ControllerWorker :: handleInputMessages ()
{
Message * message ;
while (( message = m_inputMessageQueue . pop ()) != nullptr )
{
if ( handleMessage ( * message )) {
delete message ;
}
}
}
bool GS232ControllerWorker :: handleMessage ( const Message & cmd )
{
if ( MsgConfigureGS232ControllerWorker :: match ( cmd ))
{
MsgConfigureGS232ControllerWorker & cfg = ( MsgConfigureGS232ControllerWorker & ) cmd ;
2022-11-24 16:40:36 +01:00
applySettings ( cfg . getSettings (), cfg . getSettingsKeys (), cfg . getForce ());
2020-10-27 16:22:10 +00:00
return true ;
}
else
{
return false ;
}
}
2022-11-24 16:40:36 +01:00
void GS232ControllerWorker :: applySettings ( const GS232ControllerSettings & settings , const QList < QString >& settingsKeys , bool force )
2020-10-27 16:22:10 +00:00
{
2022-11-24 16:40:36 +01:00
qDebug () << "GS232ControllerWorker::applySettings:" << settings . getDebugString ( settingsKeys , force ) << " force: " << force ;
2023-04-03 16:47:13 +01:00
if (( settingsKeys . contains ( "protocol" ) && ( settings . m_protocol != m_settings . m_protocol )) || force )
{
delete m_controllerProtocol ;
m_controllerProtocol = ControllerProtocol :: create ( settings . m_protocol );
if ( m_controllerProtocol )
{
m_controllerProtocol -> setMessageQueue ( m_msgQueueToFeature );
m_controllerProtocol -> setDevice ( m_device );
}
}
2022-11-24 16:40:36 +01:00
if ( settingsKeys . contains ( "connection" ) )
2020-10-27 16:22:10 +00:00
{
2022-11-18 10:55:15 +00:00
if ( m_device && m_device -> isOpen ())
{
2021-11-23 12:13:24 +00:00
m_device -> close ();
2022-11-18 10:55:15 +00:00
m_device = nullptr ;
2021-11-23 12:13:24 +00:00
}
2020-10-27 16:22:10 +00:00
}
2021-11-23 12:13:24 +00:00
if ( settings . m_connection == GS232ControllerSettings :: TCP )
2020-10-27 16:22:10 +00:00
{
2023-04-03 16:47:13 +01:00
if ( settingsKeys . contains ( "host" ) || settingsKeys . contains ( "port" ) || force )
{
2021-11-23 12:13:24 +00:00
m_device = openSocket ( settings );
2023-04-03 16:47:13 +01:00
if ( m_controllerProtocol ) {
m_controllerProtocol -> setDevice ( m_device );
}
2021-11-23 12:13:24 +00:00
}
}
else
{
2023-04-03 16:47:13 +01:00
if ( settingsKeys . contains ( "serialPort" ) || force )
{
2021-11-23 12:13:24 +00:00
m_device = openSerialPort ( settings );
2023-04-03 16:47:13 +01:00
if ( m_controllerProtocol ) {
m_controllerProtocol -> setDevice ( m_device );
}
}
else if ( settingsKeys . contains ( "baudRate" ) || force )
{
2021-11-23 12:13:24 +00:00
m_serialPort . setBaudRate ( settings . m_baudRate );
}
2020-10-27 16:22:10 +00:00
}
2023-01-06 09:18:02 +00:00
if ( force ) {
m_settings = settings ;
} else {
m_settings . applySettings ( settingsKeys , settings );
}
2023-04-03 16:47:13 +01:00
if ( m_controllerProtocol ) {
m_controllerProtocol -> applySettings ( settings , settingsKeys , force );
}
2022-11-18 10:55:15 +00:00
if ( m_device != nullptr )
{
// Apply offset then clamp
2021-02-26 20:27:35 +00:00
2022-11-18 10:55:15 +00:00
float azimuth , elevation ;
settings . calcTargetAzEl ( azimuth , elevation );
2021-05-30 12:38:07 +01:00
2022-11-18 10:55:15 +00:00
// Don't set if within tolerance of last setting
float azDiff = std :: abs ( azimuth - m_lastAzimuth );
float elDiff = std :: abs ( elevation - m_lastElevation );
2021-02-26 20:27:35 +00:00
2022-11-18 10:55:15 +00:00
if ((( elDiff > settings . m_tolerance ) || ( m_lastElevation == - 1 ) || force ) && ( settings . m_elevationMax != 0 ))
{
setAzimuthElevation ( azimuth , elevation );
}
else if (( azDiff > settings . m_tolerance ) || ( m_lastAzimuth == - 1 ) || force )
{
setAzimuth ( azimuth );
}
2024-02-14 13:21:26 +00:00
sendToSkyMap ( azimuth , elevation );
2020-10-27 16:22:10 +00:00
}
}
2021-11-23 12:13:24 +00:00
QIODevice * GS232ControllerWorker :: openSerialPort ( const GS232ControllerSettings & settings )
2021-02-26 20:27:35 +00:00
{
2021-11-23 12:13:24 +00:00
qDebug () << "GS232ControllerWorker::openSerialPort: " << settings . m_serialPort ;
2021-05-30 12:38:07 +01:00
if ( m_serialPort . isOpen ()) {
2021-02-26 20:27:35 +00:00
m_serialPort . close ();
2021-05-30 12:38:07 +01:00
}
2021-11-23 12:13:24 +00:00
m_lastAzimuth = - 1 ;
m_lastElevation = - 1 ;
if ( ! settings . m_serialPort . isEmpty ())
2021-02-26 20:27:35 +00:00
{
2021-11-23 12:13:24 +00:00
m_serialPort . setPortName ( settings . m_serialPort );
m_serialPort . setBaudRate ( settings . m_baudRate );
if ( ! m_serialPort . open ( QIODevice :: ReadWrite ))
{
qCritical () << "GS232ControllerWorker::openSerialPort: Failed to open serial port " << settings . m_serialPort << ". Error: " << m_serialPort . error ();
2021-02-26 20:27:35 +00:00
m_msgQueueToFeature -> push ( GS232Controller :: MsgReportWorker :: create ( QString ( "Failed to open serial port %1: %2" ). arg ( settings . m_serialPort ). arg ( m_serialPort . error ())));
2021-11-23 12:13:24 +00:00
return nullptr ;
2021-05-30 12:38:07 +01:00
}
2021-11-23 12:13:24 +00:00
else
{
return & m_serialPort ;
}
}
else
{
return nullptr ;
}
}
QIODevice * GS232ControllerWorker :: openSocket ( const GS232ControllerSettings & settings )
{
qDebug () << "GS232ControllerWorker::openSocket: " << settings . m_host << settings . m_port ;
if ( m_socket . isOpen ()) {
m_socket . close ();
2021-02-26 20:27:35 +00:00
}
m_lastAzimuth = - 1 ;
m_lastElevation = - 1 ;
2021-11-23 12:13:24 +00:00
m_socket . connectToHost ( settings . m_host , settings . m_port );
if ( m_socket . waitForConnected ( 3000 ))
{
return & m_socket ;
}
else
{
qCritical () << "GS232ControllerWorker::openSocket: Failed to connect to " << settings . m_host << settings . m_port ;
m_msgQueueToFeature -> push ( GS232Controller :: MsgReportWorker :: create ( QString ( "Failed to connect to %1:%2" ). arg ( settings . m_host ). arg ( settings . m_port )));
return nullptr ;
}
2021-02-26 20:27:35 +00:00
}
2021-05-30 12:38:07 +01:00
void GS232ControllerWorker :: setAzimuth ( float azimuth )
2020-10-27 16:22:10 +00:00
{
2023-04-03 16:47:13 +01:00
if ( m_device && m_device -> isOpen () && m_controllerProtocol ) {
m_controllerProtocol -> setAzimuth ( azimuth );
2021-05-30 12:38:07 +01:00
}
2023-04-03 16:47:13 +01:00
2021-05-30 12:38:07 +01:00
m_lastAzimuth = azimuth ;
2020-10-27 16:22:10 +00:00
}
2021-05-30 12:38:07 +01:00
void GS232ControllerWorker :: setAzimuthElevation ( float azimuth , float elevation )
2020-10-27 16:22:10 +00:00
{
2023-04-03 16:47:13 +01:00
if ( m_device && m_device -> isOpen () && m_controllerProtocol ) {
m_controllerProtocol -> setAzimuthElevation ( azimuth , elevation );
2021-05-30 12:38:07 +01:00
}
m_lastAzimuth = azimuth ;
m_lastElevation = elevation ;
2020-10-27 16:22:10 +00:00
}
2021-11-23 12:13:24 +00:00
void GS232ControllerWorker :: readData ()
2020-10-27 16:22:10 +00:00
{
2023-04-03 16:47:13 +01:00
if ( m_controllerProtocol ) {
m_controllerProtocol -> readData ();
2020-10-27 16:22:10 +00:00
}
}
void GS232ControllerWorker :: update ()
{
2021-11-23 12:13:24 +00:00
// Request current Az/El from controller
2023-04-03 16:47:13 +01:00
if ( m_device && m_device -> isOpen () && m_controllerProtocol ) {
m_controllerProtocol -> update ();
2020-10-27 16:22:10 +00:00
}
}
2023-04-03 16:47:13 +01:00
2024-02-14 13:21:26 +00:00
void GS232ControllerWorker :: sendToSkyMap ( float azimuth , float elevation )
{
QList < ObjectPipe *> targetPipes ;
MainCore :: instance () -> getMessagePipes (). getMessagePipes ( m_controller , "target" , targetPipes );
for ( const auto & pipe : targetPipes )
{
MessageQueue * messageQueue = qobject_cast < MessageQueue *> ( pipe -> m_element );
SWGSDRangel :: SWGTargetAzimuthElevation * swgTarget = new SWGSDRangel :: SWGTargetAzimuthElevation ();
swgTarget -> setName ( new QString ( "Rotator" ));
swgTarget -> setAzimuth ( azimuth );
swgTarget -> setElevation ( elevation );
messageQueue -> push ( MainCore :: MsgTargetAzimuthElevation :: create ( m_controller , swgTarget ));
}
}