summaryrefslogtreecommitdiffstats
path: root/indi-celestronaux/auxproto.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indi-celestronaux/auxproto.cpp')
-rw-r--r--indi-celestronaux/auxproto.cpp467
1 files changed, 467 insertions, 0 deletions
diff --git a/indi-celestronaux/auxproto.cpp b/indi-celestronaux/auxproto.cpp
new file mode 100644
index 0000000..9891e10
--- /dev/null
+++ b/indi-celestronaux/auxproto.cpp
@@ -0,0 +1,467 @@
+/*
+ Celestron Aux Command
+
+ Copyright (C) 2020 Paweł T. Jochym
+ Copyright (C) 2020 Fabrizio Pollastri
+ Copyright (C) 2021 Jasem Mutlaq
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "auxproto.h"
+
+#include <indilogger.h>
+#include <math.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define READ_TIMEOUT 1 // s
+#define CTS_TIMEOUT 100 // ms
+#define RTS_DELAY 50 // ms
+
+#define BUFFER_SIZE 512
+int MAX_CMD_LEN = 32;
+
+uint8_t AUXCommand::DEBUG_LEVEL = 0;
+char AUXCommand::DEVICE_NAME[64] = {0};
+//////////////////////////////////////////////////
+/////// Utility functions
+//////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void logBytes(unsigned char *buf, int n, const char *deviceName, uint32_t debugLevel)
+{
+ char hex_buffer[BUFFER_SIZE] = {0};
+ for (int i = 0; i < n; i++)
+ sprintf(hex_buffer + 3 * i, "%02X ", buf[i]);
+
+ if (n > 0)
+ hex_buffer[3 * n - 1] = '\0';
+
+ DEBUGFDEVICE(deviceName, debugLevel, "[%s]", hex_buffer);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::logResponse()
+{
+ char hex_buffer[BUFFER_SIZE] = {0}, part1[BUFFER_SIZE] = {0}, part2[BUFFER_SIZE] = {0}, part3[BUFFER_SIZE] = {0};
+ for (size_t i = 0; i < m_Data.size(); i++)
+ sprintf(hex_buffer + 3 * i, "%02X ", m_Data[i]);
+
+ if (m_Data.size() > 0)
+ hex_buffer[3 * m_Data.size() - 1] = '\0';
+
+ const char * c = commandName(m_Command);
+ const char * s = moduleName(m_Source);
+ const char * d = moduleName(m_Destination);
+
+ if (c != nullptr)
+ snprintf(part1, BUFFER_SIZE, "<%12s>", c);
+ else
+ snprintf(part1, BUFFER_SIZE, "<%02x>", m_Command);
+
+ if (s != nullptr)
+ snprintf(part2, BUFFER_SIZE, "%5s ->", s);
+ else
+ snprintf(part2, BUFFER_SIZE, "%02x ->", m_Source);
+
+ if (s != nullptr)
+ snprintf(part3, BUFFER_SIZE, "%5s", d);
+ else
+ snprintf(part3, BUFFER_SIZE, "%02x", m_Destination);
+
+ if (m_Data.size() > 0)
+ DEBUGFDEVICE(DEVICE_NAME, DEBUG_LEVEL, "RES %s%s%s [%s]", part1, part2, part3, hex_buffer);
+ else
+ DEBUGFDEVICE(DEVICE_NAME, DEBUG_LEVEL, "RES %s%s%s", part1, part2, part3);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::logCommand()
+{
+ char hex_buffer[BUFFER_SIZE] = {0}, part1[BUFFER_SIZE] = {0}, part2[BUFFER_SIZE] = {0}, part3[BUFFER_SIZE] = {0};
+ for (size_t i = 0; i < m_Data.size(); i++)
+ sprintf(hex_buffer + 3 * i, "%02X ", m_Data[i]);
+
+ if (m_Data.size() > 0)
+ hex_buffer[3 * m_Data.size() - 1] = '\0';
+
+ const char * c = commandName(m_Command);
+ const char * s = moduleName(m_Source);
+ const char * d = moduleName(m_Destination);
+
+ if (c != nullptr)
+ snprintf(part1, BUFFER_SIZE, "<%12s>", c);
+ else
+ snprintf(part1, BUFFER_SIZE, "<%02x>", m_Command);
+
+ if (s != nullptr)
+ snprintf(part2, BUFFER_SIZE, "%5s ->", s);
+ else
+ snprintf(part2, BUFFER_SIZE, "%02x ->", m_Source);
+
+ if (s != nullptr)
+ snprintf(part3, BUFFER_SIZE, "%5s", d);
+ else
+ snprintf(part3, BUFFER_SIZE, "%02x", m_Destination);
+
+ if (m_Data.size() > 0)
+ DEBUGFDEVICE(DEVICE_NAME, DEBUG_LEVEL, "CMD %s%s%s [%s]", part1, part2, part3, hex_buffer);
+ else
+ DEBUGFDEVICE(DEVICE_NAME, DEBUG_LEVEL, "CMD %s%s%s", part1, part2, part3);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::setDebugInfo(const char *deviceName, uint8_t debugLevel)
+{
+ strncpy(DEVICE_NAME, deviceName, 64);
+ DEBUG_LEVEL = debugLevel;
+}
+////////////////////////////////////////////////
+////// AUXCommand class
+////////////////////////////////////////////////
+
+AUXCommand::AUXCommand()
+{
+ m_Data.reserve(MAX_CMD_LEN);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+AUXCommand::AUXCommand(const AUXBuffer &buf)
+{
+ m_Data.reserve(MAX_CMD_LEN);
+ parseBuf(buf);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+AUXCommand::AUXCommand(AUXCommands command, AUXTargets source, AUXTargets destination, const AUXBuffer &data)
+{
+ m_Command = command;
+ m_Source = source;
+ m_Destination = destination;
+ m_Data.reserve(MAX_CMD_LEN);
+ m_Data = data;
+ len = 3 + m_Data.size();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+AUXCommand::AUXCommand(AUXCommands command, AUXTargets source, AUXTargets destination)
+{
+ m_Command = command;
+ m_Source = source;
+ m_Destination = destination;
+ m_Data.reserve(MAX_CMD_LEN);
+ len = 3 + m_Data.size();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+const char * AUXCommand::commandName(AUXCommands command) const
+{
+ if (m_Source == GPS || m_Destination == GPS)
+ {
+ switch (command)
+ {
+ case GPS_GET_LAT:
+ return "GPS_GET_LAT";
+ case GPS_GET_LONG:
+ return "GPS_GET_LONG";
+ case GPS_GET_DATE:
+ return "GPS_GET_DATE";
+ case GPS_GET_YEAR:
+ return "GPS_GET_YEAR";
+ case GPS_GET_TIME:
+ return "GPS_GET_TIME";
+ case GPS_TIME_VALID:
+ return "GPS_TIME_VALID";
+ case GPS_LINKED:
+ return "GPS_LINKED";
+ case GET_VER:
+ return "GET_VER";
+ default :
+ return nullptr;
+ }
+ }
+ else
+ {
+ switch (command)
+ {
+ case MC_GET_POSITION:
+ return "MC_GET_POSITION";
+ case MC_GOTO_FAST:
+ return "MC_GOTO_FAST";
+ case MC_SET_POSITION:
+ return "MC_SET_POSITION";
+ case MC_SET_POS_GUIDERATE:
+ return "MC_SET_POS_GUIDERATE";
+ case MC_SET_NEG_GUIDERATE:
+ return "MC_SET_NEG_GUIDERATE";
+ case MC_LEVEL_START:
+ return "MC_LEVEL_START";
+ case MC_SLEW_DONE:
+ return "MC_SLEW_DONE";
+ case MC_GOTO_SLOW:
+ return "MC_GOTO_SLOW";
+ case MC_SEEK_INDEX:
+ return "MC_SEEK_INDEX";
+ case MC_MOVE_POS:
+ return "MC_MOVE_POS";
+ case MC_MOVE_NEG:
+ return "MC_MOVE_NEG";
+ case MC_ENABLE_CORDWRAP:
+ return "MC_ENABLE_CORDWRAP";
+ case MC_DISABLE_CORDWRAP:
+ return "MC_DISABLE_CORDWRAP";
+ case MC_SET_CORDWRAP_POS:
+ return "MC_SET_CORDWRAP_POS";
+ case MC_POLL_CORDWRAP:
+ return "MC_POLL_CORDWRAP";
+ case MC_GET_CORDWRAP_POS:
+ return "MC_GET_CORDWRAP_POS";
+ case GET_VER:
+ return "GET_VER";
+ default :
+ return nullptr;
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+int AUXCommand::responseDataSize()
+{
+ if (m_Source == GPS || m_Destination == GPS)
+ {
+ switch (m_Command)
+ {
+ case GPS_GET_LAT:
+ case GPS_GET_LONG:
+ case GPS_GET_TIME:
+ return 3;
+ case GPS_GET_DATE:
+ case GPS_GET_YEAR:
+ case GET_VER:
+ return 2;
+ case GPS_TIME_VALID:
+ case GPS_LINKED:
+ return 1;
+ default :
+ return -1;
+ }
+ }
+ else
+ {
+ switch (m_Command)
+ {
+ case MC_GET_POSITION:
+ case MC_GET_CORDWRAP_POS:
+ return 3;
+ case GET_VER:
+ return 4;
+ case MC_SLEW_DONE:
+ case MC_SEEK_DONE:
+ case MC_LEVEL_DONE:
+ case MC_POLL_CORDWRAP:
+ return 1;
+ case MC_GOTO_FAST:
+ case MC_SET_POSITION:
+ case MC_SET_POS_GUIDERATE:
+ case MC_SET_NEG_GUIDERATE:
+ case MC_LEVEL_START:
+ case MC_GOTO_SLOW:
+ case MC_MOVE_POS:
+ case MC_MOVE_NEG:
+ case MC_ENABLE_CORDWRAP:
+ case MC_DISABLE_CORDWRAP:
+ case MC_SET_CORDWRAP_POS:
+ return 0;
+ case MC_SEEK_INDEX:
+ return -1;
+ default :
+ return -1;
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+const char * AUXCommand::moduleName(AUXTargets n)
+{
+ switch (n)
+ {
+ case ANY :
+ return "ANY";
+ case MB :
+ return "MB";
+ case HC :
+ return "HC";
+ case HCP :
+ return "HC+";
+ case AZM :
+ return "AZM";
+ case ALT :
+ return "ALT";
+ case APP :
+ return "APP";
+ case GPS :
+ return "GPS";
+ case WiFi:
+ return "WiFi";
+ case BAT :
+ return "BAT";
+ case CHG :
+ return "CHG";
+ case LIGHT :
+ return "LIGHT";
+ default :
+ return nullptr;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::fillBuf(AUXBuffer &buf)
+{
+ buf.resize(len + 3);
+
+ buf[0] = 0x3b;
+ buf[1] = len;
+ buf[2] = m_Source;
+ buf[3] = m_Destination;
+ buf[4] = m_Command;
+ for (uint32_t i = 0; i < m_Data.size(); i++)
+ {
+ buf[i + 5] = m_Data[i];
+ }
+ buf.back() = checksum(buf);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::parseBuf(AUXBuffer buf)
+{
+ len = buf[1];
+ m_Source = (AUXTargets)buf[2];
+ m_Destination = (AUXTargets)buf[3];
+ m_Command = (AUXCommands)buf[4];
+ m_Data = AUXBuffer(buf.begin() + 5, buf.end() - 1);
+ valid = (checksum(buf) == buf.back());
+ if (valid == false)
+ {
+ DEBUGFDEVICE(DEVICE_NAME, DEBUG_LEVEL, "Checksum error: %02x vs. %02x", checksum(buf), buf.back());
+ };
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::parseBuf(AUXBuffer buf, bool do_checksum)
+{
+ (void)do_checksum;
+
+ len = buf[1];
+ m_Source = (AUXTargets)buf[2];
+ m_Destination = (AUXTargets)buf[3];
+ m_Command = (AUXCommands)buf[4];
+ if (buf.size() > 5)
+ m_Data = AUXBuffer(buf.begin() + 5, buf.end());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+unsigned char AUXCommand::checksum(AUXBuffer buf)
+{
+ int l = buf[1];
+ int cs = 0;
+ for (int i = 1; i < l + 2; i++)
+ {
+ cs += buf[i];
+ }
+ return (unsigned char)(((~cs) + 1) & 0xFF);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// Return 8, 16, or 24bit value as dictacted by the data response size.
+/////////////////////////////////////////////////////////////////////////////////////
+uint32_t AUXCommand::getData()
+{
+ uint32_t value = 0;
+ switch (m_Data.size())
+ {
+ case 3:
+ value = (m_Data[0] << 16) | (m_Data[1] << 8) | m_Data[2];
+ break;
+
+ case 2:
+ value = (m_Data[0] << 8) | m_Data[1];
+ break;
+
+ case 1:
+ value = m_Data[0];
+ break;
+ }
+
+ return value;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// Set encoder position in steps.
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::setData(uint32_t value, uint8_t bytes)
+{
+ m_Data.resize(bytes);
+ switch (bytes)
+ {
+ case 1:
+ len = 4;
+ m_Data[0] = static_cast<uint8_t>(value >> 0 & 0xff);
+ break;
+ case 2:
+ len = 5;
+ m_Data[1] = static_cast<uint8_t>(value >> 0 & 0xff);
+ m_Data[0] = static_cast<uint8_t>(value >> 8 & 0xff);
+ break;
+
+ case 3:
+ default:
+ len = 6;
+ m_Data[2] = static_cast<uint8_t>(value >> 0 & 0xff);
+ m_Data[1] = static_cast<uint8_t>(value >> 8 & 0xff);
+ m_Data[0] = static_cast<uint8_t>(value >> 16 & 0xff);
+ break;
+ }
+}