| 
									
										
										
										
											2023-04-03 16:47:13 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							| 
									
										
										
										
											2023-11-18 13:12:18 +01:00
										 |  |  | // Copyright (C) 2023 Jon Beniston, M7RCE <jon@beniston.com>                     //
 | 
					
						
							| 
									
										
										
										
											2023-04-03 16:47:13 +01: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/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <cmath>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <QDebug>
 | 
					
						
							|  |  |  | #include <QRegularExpression>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "gs232protocol.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GS232Protocol::GS232Protocol() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GS232Protocol::setAzimuth(float azimuth) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2025-08-08 17:18:15 +01:00
										 |  |  |     QString cmd = QString("M%1%2").arg((int)std::round(azimuth), 3, 10, QLatin1Char('0')).arg(lineEnding()); | 
					
						
							| 
									
										
										
										
											2023-04-03 16:47:13 +01:00
										 |  |  |     QByteArray data = cmd.toLatin1(); | 
					
						
							|  |  |  |     m_device->write(data); | 
					
						
							|  |  |  |     m_lastAzimuth = azimuth; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GS232Protocol::setAzimuthElevation(float azimuth, float elevation) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2025-08-08 17:18:15 +01:00
										 |  |  |     QString cmd = QString("W%1 %2%3").arg((int)std::round(azimuth), 3, 10, QLatin1Char('0')).arg((int)std::round(elevation), 3, 10, QLatin1Char('0')).arg(lineEnding()); | 
					
						
							| 
									
										
										
										
											2023-04-03 16:47:13 +01:00
										 |  |  |     QByteArray data = cmd.toLatin1(); | 
					
						
							|  |  |  |     m_device->write(data); | 
					
						
							|  |  |  |     ControllerProtocol::setAzimuthElevation(azimuth, elevation); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Handle data received from controller
 | 
					
						
							|  |  |  | void GS232Protocol::readData() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char buf[1024]; | 
					
						
							|  |  |  |     qint64 len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (m_device->canReadLine()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         len = m_device->readLine(buf, sizeof(buf)); | 
					
						
							|  |  |  |         if (len != -1) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             QString response = QString::fromUtf8(buf, len); | 
					
						
							| 
									
										
										
										
											2025-04-20 17:56:11 +10:00
										 |  |  |             // Handle both formats:
 | 
					
						
							|  |  |  |             // 1. AZ=XXX EL=XXX (MD-02 can return negative angles like AZ=-00 EL=-00)
 | 
					
						
							|  |  |  |             // 2. +XXXX+YYYY (direct angle format)
 | 
					
						
							|  |  |  |             QRegularExpression reAzEl("AZ=([-\\d]\\d\\d) *EL=([-\\d]\\d\\d)"); | 
					
						
							|  |  |  |             QRegularExpression reAngles("([+-]\\d{4})([+-]\\d{4})"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             QRegularExpressionMatch matchAzEl = reAzEl.match(response); | 
					
						
							|  |  |  |             QRegularExpressionMatch matchAngles = reAngles.match(response); | 
					
						
							|  |  |  |             if (matchAzEl.hasMatch()) | 
					
						
							| 
									
										
										
										
											2023-04-03 16:47:13 +01:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2025-04-20 17:56:11 +10:00
										 |  |  |                 QString az = matchAzEl.captured(1); | 
					
						
							|  |  |  |                 QString el = matchAzEl.captured(2); | 
					
						
							| 
									
										
										
										
											2025-04-21 19:22:21 +10:00
										 |  |  |                 //qDebug() << "GS232Protocol::readData read Az " << az << " El " << el;
 | 
					
						
							| 
									
										
										
										
											2023-04-03 16:47:13 +01:00
										 |  |  |                 reportAzEl(az.toFloat(), el.toFloat()); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2025-04-20 17:56:11 +10:00
										 |  |  |             else if (matchAngles.hasMatch()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Convert from +XXXX format to float
 | 
					
						
							|  |  |  |                 QString az = matchAngles.captured(1); | 
					
						
							|  |  |  |                 QString el = matchAngles.captured(2); | 
					
						
							| 
									
										
										
										
											2025-04-21 19:22:21 +10:00
										 |  |  |                 //qDebug() << "GS232Protocol::readData read direct angles Az " << az << " El " << el;
 | 
					
						
							| 
									
										
										
										
											2025-04-20 17:56:11 +10:00
										 |  |  |                 // The format gives angles in tenths of a degree, so divide by 10
 | 
					
						
							|  |  |  |                 reportAzEl(az.toFloat()/10.0f, el.toFloat()/10.0f); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-04-03 16:47:13 +01:00
										 |  |  |             else if (response == "\r\n") | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Ignore
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2025-04-20 17:56:11 +10:00
										 |  |  |                 qWarning() << "GS232Protocol::readData - unexpected GS-232 response \"" << response << "\""; | 
					
						
							| 
									
										
										
										
											2023-04-03 16:47:13 +01:00
										 |  |  |                 reportError(QString("Unexpected GS-232 response: %1").arg(response)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Request current Az/El from controller
 | 
					
						
							|  |  |  | void GS232Protocol::update() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2025-08-08 17:18:15 +01:00
										 |  |  |     QString cmd = QString("C2%1").arg(lineEnding()); | 
					
						
							|  |  |  |     QByteArray data = cmd.toLatin1(); | 
					
						
							|  |  |  |     m_device->write(data); | 
					
						
							| 
									
										
										
										
											2023-04-03 16:47:13 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-08 17:18:15 +01:00
										 |  |  | QString GS232Protocol::lineEnding() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_settings.m_lineEnding == GS232ControllerSettings::CRLF) { | 
					
						
							|  |  |  |         return "\r\n"; | 
					
						
							|  |  |  |     } else if (m_settings.m_lineEnding == GS232ControllerSettings::CR) { | 
					
						
							|  |  |  |         return "\r"; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         return "\n"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |